单列模式-双重锁校验解析

public class Singleton {  
    private volatile static Singleton singleton;  
    private Singleton (){}  
    public static Singleton getSingleton() {  
    if (singleton == null) {  
        synchronized (Singleton.class) {  
        if (singleton == null) {  
            singleton = new Singleton();  
        }  
        }  
    }  
    return singleton;  
    }  
}  

这里第一个if,第二个if,synchronized 的本质都是为了避免产生多实例,但侧重点个不相同。

第一个if判断很好理解,即如果成员变量singleton已经被实例化了,当然不需要重复创建了,直接返回该成员变量即可。

使用synchronized的目的是保证在多线程环境中,同一时间只有一个线程执行new操作。同时synchronized也可以保证线程可见性,即当当前线程实例化对象之后,其他线程获取锁之后能够感知到上一个线程创建的对象,从而避免重复创建。假设A,B两个线程同时执行 getSingleton() 操作,B线程先获取锁,A线程阻塞。当B线程执行new操作,创建完对象后,释放锁时会立即将 singleton的值刷新回主内存,当A线程拿到锁时,A线程会从主内存中获取最新的的singleton值,此时singleton已经有值了,该值即为B线程创建的对象的地址,所以A线程在执行第二个if判断时恒为false,不会执行new操作。 

第二个if判断是为了保证在多线程环境中,对象只被new一次,即假如已经有线程创建了对象,则当前线程无需再执行new操作。

volatile既可以保证线程可见性,也可以防止指令重排序。这里synchronized已经保证了线程可见性,所以这里的volatile主要用来防止指令重排序,因为new操作,赋值操作,return操作不是原子操作,它们执行的顺序可能是乱序的,所以要使用volatile。

附带一张volatile的原理图       

 

 

                                                                                                                                                                                               

posted @ 2020-12-08 14:19  Miss丶榛子小姐  阅读(148)  评论(0编辑  收藏  举报