Java线程安全的单例模式

在Java并发编程实践(JAVA concurrency in practice)中的第十六章(Java存储模型)中.
有讲到对象安全发布.
其中就是以单例模式来说明这个安全初始化技巧的.这是学习分析总结如下:
   
引用

不正确发布带来的风险的真正原因是在"发布共享对象"与从"另一个线程访问它"之间,缺少happens-before排序.

     不安全的发布.
发布(Publishing):
引用

发布(Publishing)一个对象的意思是使它能够被当前范围之处的代码所使用.比如将一个引用
存储到其他代码可以访问的地方.在一个非千私有的方法中返回这个引用,也可以把它传递到其他类的方法中.在很多情况下,我们需要确保对象及它们的内部状态不被暴露(publish).


代码清单1:不安全的惰性初始化:
public class UnsafeLazyInitialization{
 private static Resource resource;
 public static Resource getInstance(){
   if(resource == null){
     resource = new Resource();
   }
return resource;
}
}


引用

除了不可变对象以外,使用被另一个线程初始化的对象,是不安全的,除非对象的发布是happens-before于对象的消费线程使用它.

安全初始化技巧:
代码清单2 线程安全的惰性初始化
public class SafeLazyInitialization{
 private static Resource resource;
  public synchronized static Resource getInstance(){
        if(Resource == null){
         resource = new Resource();
        }
  }
}



代码清单3 主动初始化
public class EagerInitialization{
  private static Resource resource = new Resource();
  public static Resource getResource() {
   return resource;
  }
}


像上面那样,使用主动的初始化,避免了每次调用SafeLazyInitialization的getInstance()的同步开销.这项技术可以和JVM的惰性类加载相结合,
创建一种惰性初始化技术,使得在通常的代码路径中都不需要同步.清单4的惰性初始化holder类技巧.使用一个专门用来初始化Resource的类.JVM将ResourceHolder的初始化被 延迟到真正使用它的时刻.因为Resource是在静态初始进行初始化的,所以不再需要额外的同步.,线程第一次调用getResource,引起ResourceHolder的加载和初始化,这个时候,正是静态初始阶段Resource完成初始化发生的时间.

清单4惰性初始化Holder类技巧
public class ResourceFactory{
 private static ResourceHolder {
     public static Resource resource = new Resource();
 }
public static Resource getResource(){
 return ResourceHolder.resource;
}
}

你可能感兴趣的:(java,单例模式,concurrency,类加载)