单例模式1:
此种模式在多线程模式下会有问题
public class Singleton{ //私有静态实例,防止被引用,此处设置为null,是为了延迟加载 private static Sigleton instance = null; //私有构造方法,防止被实例化 private Singleton(){ } //静态方法,创建实例 public static Singleton getInstance(){ if(instance == null){ instance = new Singleton(); } } //若该类被用于序列化,可以保证序列号前后保持一致 public Object readResolve(){ return instace; } }
==================================华丽丽的分割线====================================
单例模式2
能解决多线程的问题;
但又会出现其它问题:由于java中创建对象和赋值是分开执行的,所以对于instance=new Singleton()其实是分开两步的,java不保证其中的执行顺序,可能会出现JVM为新的Singleton实例分配空间,然后直接赋值给成员instance,然后再去初始化instance实例,这样就有可能出错了
例子:A,B两个线程同时进入第一个if判断
A首先进入synchronized代码块,由于instance此时为null,则执行instance = new Singleton()
JVM会先分配给Singleton一些空白内存,并赋值给instance,不过此时JVM并没有开始初始化Singleton,然后A离开方法;
B进入synchronized代码块,由于instance不为null,所以马上离开并把结果返回给调用者;
至此,B线程要Singleton实例,却发现未被实例化,从而出错
public class Singleton{ //私有静态实例,防止被引用,此处设置为null,是为了延迟加载 private static Sigleton instance = null; //私有构造方法,防止被实例化 private Singleton(){ } //静态方法,创建实例 public static Singleton getInstance(){ if(instance == null){ synchronized(instance){ if(instance == null){ instance = new Singleton(); } } } } //若该类被用于序列化,可以保证序列号前后保持一致 public Object readResolve(){ return instace; } }
==================================华丽丽的分割线====================================
单例模式3
保证多线程环境,保证互斥.
JVM能保证一个类被加载的时候,加载过程是互斥的,这样当第一次调用getInstance的时候
JVM能够帮助我们保证instance只被创建一次,并且保证赋值给instace的结果已初始化完毕;
同时该方法也只会在第一次调用的时候使用互斥机制,这样也解决低性能的问题;
public class Singleton{ //私有构造方法,防止被实例化 private Singleton(){ } //使用一个内部类来维护单例 private static class SingleFactory(){ private static Sigleton instance = null; } //静态方法,创建实例 public static Singleton getInstance(){ return SingleFactory.instace; } //若该类被用于序列化,可以保证序列号前后保持一致 public Object readResolve(){ return instace; } }