1. 常见方式
java
保证线程安全条件下有三种方式:安全
提早初始化:类加载时就建立一个对象,app
延迟初始化
ide
DCL:双重检查,JDK5.0后单例实例加volatile修饰线程
占位类:推迟占位类的初始化对象
提早初始化可能影响程序启动时间以及没必要要高开销操做较少采用
排序
2. DCLget
public class DoubleCheckLocking { private static Resource resource; public static Resource getInstance(){ if(resource == null){ synchronized (DoubleCheckLocking.class){ if (resource == null){ resource = new Resource() } } } return resource } }
上述代码的问题在于在没有同步的状况下读取一个共享对象,可能发生的状况是获取一个没有完成初始化的对象,部分属性是失效的。同步
在缺乏Happens-Before关系时,可能出现指令重排序。初始化对象若是须要写入多个变量,发布对象引用也须要写入一个变量。上述没法保证发布引用在另外一个线程加载该引用前,新对象引用的写操做与属性的写操做会重排,这样新线程会看到引用的最新值,可是部分属性失效。it
JDK5.0后为resource家volatile修饰能够使用DCL,可是这种方法已经被普遍废弃,占位模式更容易理解
3. 占位类
public class DoubleCheckLocking { private static class ResourceHolder{ public static Resource resource = new Resource(); } public static Resource getInstance(){ return ResourceHolder.resource; } }