单例模式与volatile

public class SingletonDemo{
	private static SingletonDemo instance==null;

	private SingletonDemo(){
		System.out.println(Thread.currentThread.getName+"\t 我是构造方法")
	}
	
	public static SingletonDemo getInstance(){
		if(instance==null){
			synchroized(SingletonDemo.class){
				if(instance==null){
					instance=new SingletonDemo();
				}
			}
		}
		return instance;
	}
} 

这是我们通常学习的单例模式,该程序使用了DCL(double check lock 双端检索机制),在单机模式中是不会出错的,但是在多线程环境下,编译器和处理器为提高程序执行效率,可能会对指令进行重排,如果没有控制好指令重排,则可能会出现错误(但机率非常小,可能上千万次才会出现一次)。

原因是instance=new SingletonDemo();这行代码可能会出现问题,在某一个线程执行第一次检测时,检测到instance不为null,但instance此时还没完成初始化。

instance=new SingletonDemo();可以分为下面三步(伪代码)
1.memory=allocate;//分配对象内存空间
2.instance(memory);//初始化对象;
3.instance=memory;//设置instance对象指向内存空间,此时instance!=null!
以为2和3不存在指令间的依赖关系,所以在多线程环境中可能进行指令重排,即instance=new SingletonDemo();实际的执行顺序为132,在执行3时,检测到instance不等于空,但实际上instance对象还没进行初始化从而造成线程安全问题。

解决的方法:在定义instance对象时加上volatile修饰,禁止指令重排。
private static volatile SingletonDemo instance==null;

发布了2 篇原创文章 · 获赞 11 · 访问量 787

猜你喜欢

转载自blog.csdn.net/qq_39285490/article/details/104279694