public class SingletonDemo1 {
//类初始化时立即加载这个对象(没有延时加载的优势),加载类时,天然是线程安全的!
private static SingletonDemo1 instance = new SingletonDemo1();
//-------私有构造器-------
private SingletonDemo1() {
}//-------方法没有同步,调用效率高-------
public static SingletonDemo1 getInstance() {
return instance;
}
}
饿汉式单例模式代码中,static变量会在类装载时初始化,此时也不会涉及多个线程对象访问该对象的问 题。虚拟机保证只会装载一次该类,肯定不会发生并发访问的问题。因此,可以省略synchronized关键字。
问题:如果只是加载本类,而不是要调用getInstance(),甚至永远没有调用,则会造成资源浪费!
public class SingletonDemo2 {
//-------类初始化时,不初始化这个对象(延时加载,真正用到时再创建)-------
private static SingletonDemo2 instance;
//-------私有构造器-------
private SingletonDemo2() {
}//-------方法同步,调用效率低-------
public static synchronized SingletonDemo2 getInstance() {
if(instance == null) {
instance = new SingletonDemo2();
}
return instance;
}
}
public class SingletonDemo3 {
private static SingletonDemo3 instance = null;
public static SingletonDemo3 getInstance() {
if (instance == null) {
SingletonDemo3 sc;
synchronized (SingletonDemo3.class) {
sc = instance;
if (sc == null) {
synchronized (SingletonDemo3.class) {
if(sc == null) {
sc = new SingletonDemo3();
}
}
instance = sc;
}
}
}
return instance;
}
private SingletonDemo3() {
}
}
这个模式将同步内容下方到if内部,提高了执行的效率 不必每次获取对象时都进行同步,只有第一次才同步 创建了以后就没必要了。
问题:由于编译器优化原因和JVM底层内部模型原因, 偶尔会出问题。不建议使用
public class SingletonDemo4 {
private static class SingletonClassInstance{
private static final SingletonDemo4 instance = new SingletonDemo4();
}
private SingletonDemo4() {
}
public static SingletonDemo4 getInstance() {
//返回内部类的实例
return SingletonClassInstance.instance;
}
}
public enum SingletonDemo5 {
//这个枚举元素,本身就是单例对象
INSTANCE;
//添加自己需要的操作
public void singletonOperation() {
}
}
优点:
实现简单 – 枚举本身就是单例模式。由JVM从根本上提供保障!避免通过反射和反序列化的漏洞!
缺点:
无延迟加载
懒汉式(线程安全,调用效率不高。 但是,可以延时加载。)
双重检测锁式(由于JVM底层内部模型原因,偶尔会出问题。不建议使用)
静态内部类式(线程安全,调用效率高。 但是,可以延时加载)
枚举式(线程安全,调用效率高,不能延时加载。并且可以天然的防止反射和反序列 化漏洞!)
单例对象 占用 资源 少,不需要 延时加载:
枚举式 好于 饿汉式
单例对象 占用 资源 大,需要 延时加载:
静态内部类式 好于 懒汉式