虽然从Java5之后可以通过将字段声明为volatile来避免了java中double check失效问题,但还是有点不大明白,主要由以下两点:
- Java code
public class lazySingleton { private static volatile lazySingleton m_instance=null; private lazySingleton() { // TODO Auto-generated constructor stub System.out.println("构造函数"); } public static lazySingleton getInstance(){ if(m_instance==null){ synchronized (lazySingleton.class) { if(m_instance==null){ m_instance=new lazySingleton(); //疑惑一 } } } return m_instance; } public void print(){ System.out.println("print"); } public static void main(String[] args) { // TODO Auto-generated method stub lazySingleton.getInstance().print(); }}
1.能简要描述下到底是什么原因导致double check失效的吗?虽然很多地方看到是由于Java 编译器中LazySingleton类的初始化与instance变量的赋值顺序不可预料。以上代码“疑惑一”处,如果构造函数没有执行完毕,m_instance不是仍然为null吗?再说,如果构造函数没有执行完毕,会解锁吗?
2.外部加锁代码,每次都synchronized
- Java code
synchronized public static lazySingleton getInstance(){ if(m_instance==null){ m_instance=new lazySingleton(); } return m_instance; }
为什么此处就不会出现上述的问题呢,个人感觉同样会出现一个线程的构造函数没有执行完毕,但已经对m_instance赋值,导致别的线程引用未知指向的m_instance吗?
------解决方案--------------------------------------------------------
第一,你没有理解Singleton模式,要不然你不会问“如果构造函数没有执行完毕,m_instance不是仍然为null吗?”
第二,你也没有理解synchronized 放在方法前面的含义,不然你就会知道第二种方法是无论如何也不会出现问题的。
第三,我觉得第一段代码是没有问题的。
------解决方案--------------------------------------------------------
双检锁失效的主要论点是:
m_instance=new lazySingleton();
这句话会被优化时的指令重排,以至于先赋值,再执行对象初始化:
m_instance = 对象内存位置;
对象.构造函数();
以至于某线程可能得到一个未初始化完毕的对象,所以关键问题已经不是在synchronized身上,而是 if
- Java code
public static lazySingleton getInstance(){ if(m_instance==null){ // B线程检测到m_instance不为空 synchronized (lazySingleton.class) { if(m_instance==null){ m_instance=new lazySingleton(); // A线程被指令重排了,刚好先赋值了;但还没执行完构造函数。 } } } return m_instance; // 后面B线程执行时将引发:对象尚未初始化错误。 }
------解决方案--------------------------------------------------------
http://icyfenix.iteye.com/blog/575052
------解决方案--------------------------------------------------------
不是你说的那个意思啊。
没加volatile的问题最多也只是B线程看不到A线程的赋值而已,那么无非是if条件成立,进入synchronized进行等待。
恰恰是加了volatile,才让B线程能更好的立即看到A线程的赋值;从而B线程可以调用一个无效对象。
------解决方案--------------------------------------------------------
诚惶诚恐
volatile的作用:http://www.ticmy.com/?p=118
如果楼主只是从源码角度去看多线程代码,很多并发问题是看不出来的,如果以前没有接触过,可先查阅 java内存模型 (Java Memory Model) 相关资料