栏目分类:
子分类:
返回
终身学习网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
终身学习网 > IT > 软件开发 > 后端开发 > Java

双重检查锁定的问题 ---单例模式

Java 更新时间:发布时间: 百科书网 趣学号

双重检查锁定的问题
      • 问题原因
      • 解决方案

我们在开发过程中,为了限制资源的访问,常常使用单例模式,为了防止单例模式下大对象的开销,可以使用延迟加载的方式在第一次获取对象时来初始化他。
看一下下面的代码

public class UnsafeLazyInitialization { 
	private static Instance instance; 
	public static Instance getInstance() {
		 if (instance == null)
			instance = new Instance(); 
		return instance; 
		}
}

在单线程的情况下这种方式是一个很好的选择,但是再多线程情况下,实例为空的判断和初始化实例这部分临界区存在线程安全的问题
对于多线程的模式下为了保证线程安全下可以使用 java synchronized关键字,保证竞态资源的访问。

public class SafeLazyInitialization { 
	private static Instance instance; 
	public synchronized static Instance getInstance() { 
		if (instance == null) 
			instance = new Instance();
		return instance;
	 }
}

上述的代中对 getInstance 加锁,防止线程不安全问题,在 instance 对象访问量较少的情况下是一个很好的选择,但是如果 instance 已经初始化完成,此时就没有必要使用锁,增加了不必要的开销。

public class DoubleCheckedLocking { 
	private static Instance instance; 
	public static Instance getInstance() {
		 if (instance == null) {
			synchronized (DoubleCheckedLocking.class) { 
				if (instance == null)
					instance = new Instance();
			}	
		 } 
		return instance;
	}
}

利用双重检查锁定来降低锁的开销,看起来似乎很完美,但是这是一个错误的优化,问题就出现在下面这一行代码中
代码读 取到instance不为null时,instance引用的对象有可能还没有完成初始化。

instance = new Instance();
问题原因
	创建一个对象 instance = new Instance(); 可以分为下面三个步骤
	1.开辟内存空间  memory = allocate();    // A
	2.对象初始化     ctorInstance(memory);  // B
	3.设置instance指向刚分配的内存地址 instance = memory; //C

这里的 A、B、C 可能存在重排序的问题 ,以为 A happens-before B 、A happens-before C ,但是 B、C 没有依赖关系,所以初始化对象的执行顺序可能是 A-B-C 或者 A-C-B, 当执行顺序为 A-C-B 时 就存在 当 instance 不为 null 时,instance 没有初始化完成。

解决方案
  1. 不允许出现重排序
    volatile 修饰 instance 禁止重排序
public class SafeDoubleCheckedLocking {
	private volatile static Instance instance;
	public static Instance getInstance() { 
	   if (instance == null) {
		   synchronized (SafeDoubleCheckedLocking.class) { 
			   if (instance == null) 
			   	instance = new Instance();
		    }
	   } 
	   return instance;
	}
}
  1. 重排序对其他线程不可见
    利用类加载机制进行初始化
public class InstanceFactory { 
	private static class InstanceHolder { 
		public static Instance instance = new Instance();
	} 
	public static Instance getInstance() { 
		return InstanceHolder.instance ; // 这里将导致InstanceHolder类被初始化
	}
}
转载请注明:文章转载自 www.051e.com
本文地址:http://www.051e.com/it/276536.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 ©2023-2025 051e.com

ICP备案号:京ICP备12030808号