开发者社区> 问答> 正文

Java中的双重检查成例:报错

public class LazySingleton {
	private static LazySingleton m_instance = null;
	private LazySingleton(){}
	//静态工厂方法
	public static LazySingleton getInstance(){
		if(m_instance == null){
			synchronized (LazySingleton.class) {
				if(m_instance == null){
					m_instance = new LazySingleton();
				}
			}
		}
		return m_instance;
	}
}
上面是一段使用双重检查成例的懒汉式单例类。 大家能告诉我下面的说法对吗?在系统中有可能发生吗? 在Java编译器中,由于m_instance变量的赋值和LazySingleton类的初始化顺序是不确定的,所以某线程读取m_instance的引用,调用这个对象的方法时,对象的初始化尚未完成(也就是,m_instance = new LazySingleton();这段中的new LazySingleton()还没有执行完)导致出现错误。

展开
收起
kun坤 2020-06-08 16:57:02 428 0
1 条回答
写回答
取消 提交回答
  • 构造方法里Thread.sleep(10),模拟下类的构造过程,用多线程去getInstance(),再print(m_instance),就会发现地址值不一样了,说明构造了多个对象,这么写就是防止这种情况。其实也并不需要用DCL这种方式,饿汉模式就能避免这种情况。######嗯嗯 sleep() 要的就是这个 非常感谢######个人是这么理解的,假如有两个线程 A,B同时调用 getInstance方法,当A线程运行到代码第6行时,时间片被撤出,B线程运行getInstance方法,拿到锁之后,对变量进行赋值,这是为了防止多线程的情况下,会造成建立多个对象。######  private static LazySingleton m_instance = new LazySingleton(); 这样简单

    ######嗯 饿汉式单例和带有同步机制的懒汉式单例都应该没问题######如果初始化开销大,这种方式就不太好。但是一般的,这种方式比较好。我也喜欢这种方式。###### 对的 可以参考《Java concurrency in practice》16.2.4节
    如果必须实现lazy initialization,可以利用JVM的lazy class loading机制。 ######额 我找找这本书######写两个线程,打个断点不就可以观察了吗?或者在 if(m_instance == null)后面sleep()几秒,如果没有双重检查,你就会看到两个线程分别分别产生了不同的对象,二者拿到的对象不是同一个,因此不能保证单例######sleep正中靶心###### Intuitively, this algorithm seems like an efficient solution to the problem. However, this technique has many subtle problems and should usually be avoided. For example, consider the following sequence of events:

    1. Thread A notices that the value is not initialized, so it obtains the lock and begins to initialize the value.
    2. Due to the semantics of some programming languages, the code generated by the compiler is allowed to update the shared variable to point to a partially constructed object before A has finished performing the initialization. For example, in Java if a call to a constructor has been inlined then the shared variable may immediately be updated once the storage has been allocated but before the inlined constructor initializes the object.[4]
    3. Thread B notices that the shared variable has been initialized (or so it appears), and returns its value. Because thread B believes the value is already initialized, it does not acquire the lock. If B uses the object before all of the initialization done by A is seen by B (either because A has not finished initializing it or because some of the initialized values in the object have not yet percolated to the memory B uses (cache coherence)), the program will likely crash.(wiki)
    ######嗯嗯 就是这个意思 本来很晕 看了大家的回答 确实这段代码在java中就是错误的
    2020-06-08 16:57:08
    赞同 展开评论 打赏
问答排行榜
最热
最新

相关电子书

更多
Spring Cloud Alibaba - 重新定义 Java Cloud-Native 立即下载
The Reactive Cloud Native Arch 立即下载
JAVA开发手册1.5.0 立即下载