package com.yunding.concurrent;

/**
 * 多线程环境下的单例模式: doubleChecked + volatile (双重检测 + 避免happenBefore)
 * 
 * 实例化对象的三个步骤: 1. 开辟空间 2. 初始化对象 3. 把对象的地址赋给引用变量
 * 
 * @author beOkWithAnything
 *
 */
public class DoubleCheckedLocking {

	/**
	 * 3. 提供 volatile修饰的 私有的静态属性 DoubleChecking 可能会存在指令重排(happenBefore):
	 * 如果初始化操作比较耗时,可能会发生指令重排:对象未初始化完成就把对象的地址赋给引用变量
	 * 由于存在DoubleChecking,新的线程就会访问到未初始化完成的对象,加入volatile来避免指令重排(保证对象使用时内容同步更新)
	 */
	private static volatile DoubleCheckedLocking instance;

	// 构造器私有化
	private DoubleCheckedLocking() {
	}

	// 提供公共的静态方法: 获取属性
	public static DoubleCheckedLocking getInstance() {

		/**
		 * 2. 已经存在对象时: 避免不必要的同步
		 * 如果没有双重检测(DoubleChecked),每个线程都要去等待当前持有instance锁的线程判断完成才能返回实例
		 */
		if (null != instance) {
			return instance;
		}
		/**
		 * 1. 加锁: 如果初始化对象的步骤比较耗时,多线程环境下不加锁会 重复创建对象
		 */
		synchronized (instance) {
			if (null == instance) {
				instance = new DoubleCheckedLocking();
			}
		}
		return instance;
	}

}