这是head first 设计模式中单例模式第182页的一段代码
public class Singleton { // 为什么要使用volatile关键字? private volatile static Singleton uniqueInstance; private Singleton() {} public static Singleton getInstance() { if (uniqueInstance == null) { /* 为什么要使用synchronized (Singleton.class),使用synchronized(this)或者 synchronized(uniqueInstance)不行吗?而且synchronized(uniqueInstance)的效率更加高?*/ synchronized (Singleton.class) { if (uniqueInstance == null) { uniqueInstance = new Singleton(); } } } return uniqueInstance; } }
问题一:为什么要使用volatierle关键字?
问题二:为什么要使用synchronized (Singleton.class),使用synchronized(this),或者synchronized(uniqueInstance)不行吗?而且synchronized(uniqueInstance)的效率更加高?
对于问题一
public class Foo extends Thread { private volatile boolean close = false; public void run() { while(!close) { // do work } } public void close() { close = true; // interrupt here if needed } }
you need volatile because the thread reading close in the while loop is different from the one that calls close(). Without volatile, the thread running the loop may never see the change to close.
对于问题二,作者并没有给出原因,只贴出了代码
static void myMethod() { synchronized(MyClass.class) { //code } } is equivalent to static synchronized void myMethod() { //code } and void myMethod() { synchronized(this) { //code } } is equivalent to synchronized void myMethod() { //code }
关于问题一我再补充一点:
上述答案其实都不太恰当,volatile
在如上单例模式中起的作用其实并不是第一时间读到。
假设没有加volatile
,第一时间读不到,那么它的值还是null(?), 在进去里面的synchronized
时就会读到最新值(synchronized
保证了原子性和可见性),看起来volatile
可有可无。
这里的volatile
的语意是在JDK5
后增强的,可以理解为原子的
,如果不加,上面(?)处就可能不为null
也不为正确值(尽管这个概率微乎其微),是一个中间值(不是完整的对象),这样就不能构造正确的单例。
第一个问题:
volatile可以保证共享变量的"可见性",意思就是说当一个线程修改了变量,另外的线程能读到这个修改的值;
实现是通过lock指令,lock指令回将处理器缓存写回到内存,当一个处理器缓存写回到内存会导致其他处理器的缓存失效,当其他处理器获取缓存数据发现缓存失效就会重新从内存中读取数据
1、volatile
保证了uniqueInstance
的修改对各个线程的可见性。
2、这是个static
方法synchronized(this)
肯定是不行的,因为没有this
。再说synchronized(uniqueInstance)
,synchronized
是针对对象而言的,对象都是堆里的对象,但是初始化状态下uniqueInstance
是null
,只是栈里的一个标识,在堆里没有。我试了一下synchronized(null)
会报空指针异常。