手写双重校验锁实现对象单例并附详细解释说明
作者:互联网
public class Singleton{
private volatile static Singleton uniqueInstance;
private Singleton(){
}
public static Singleton getUniqueInstance(){
if(uniqueInstance==null){
synchronized(Singleton.class){
if(uniqueInstance==null){
uniqueInstance=new Singleton();
}
}
}
return uniqueInstance;
}
}
说明:
- 由于构造函数私有,我们获取Singleton类的实例化对象只能通过Singleton.getUniqueInstance()的方式,而无法在外界通过new或者其他方法创建此类的实例,并且由于此成员变量被static修饰,使得实例对象属于类本身且只有唯一一个。
- volatile关键字可以防止jvm指令重排
因为 uniqueInstance = new Singleton() 这句话可以分为三步:
1. 为 singleton 分配内存空间;
2. 初始化 singleton;
3. 将 singleton 指向分配的内存空间。
但是由于JVM具有指令重排的特性,执行顺序有可能变成 1-3-2。 指令重排在单线程下不会出现问题,但是在多线程下会导致一个线程获得一个未初始化的实例。例如:线程T1执行了1和3,此时T2调用 getInstance() 后发现 singleton 不为空,因此返回 singleton, 但是此时的 singleton 还没有被初始化。
使用 volatile 会禁止JVM指令重排,从而保证在多线程下也能正常执行。
- synchronized加在getUniqueInstance方法上这样虽然能保证只有一个线程执行getUniqueInstance()方法,但是缺点在于锁的粒度太大了,多个线程同时调用getUniqueInstance()时,其他线程都会被阻塞,毕竟大多数情况下对象已经存在。
- 第二次判断是为了防止多个线程同时完成第一次判断为null,A线程获得锁后new一个对象释放锁,此时B线程也获得锁如果没有第二次判断B线程也会new一个对象。
标签:Singleton,校验,singleton,getUniqueInstance,uniqueInstance,线程,单例,new,手写 来源: https://blog.csdn.net/qq_28123419/article/details/114645598