线程安全的单例模式

单例模式是最简单的设计模式,但是使用时要注意线程安全问题,以下是单例模式的几种写法,比较好的方法是基于类初始化的方式,既能实现线程安全,又可以实现延迟加载。饿汉模式可实现线程安全,但是效率可能会出现问题。还应注意双重锁的检测,由于指令重排并不能保证线程安全
一.饿汉式:
public class Singleton{
     private final static Singleton instance=new Singleton();//无论用不用,类加载时都会new
     private Singleton(){}//必须是private 的,保证用户不能手动new 一个实例
     public Singleton getInstance(){
          return instance;
     }
}//线程安全,因为static 的变量一个类只有一份
二.懒汉式:
1.public class Singleton{
          private static Singleton instance=null;
          private Singleton(){}
          public static Singleton getInstance(){
               if(instance==null)
                    instance=new Singleton();
               return instance;
          }
}
第一种方法适用于单线程,非线程安全。 static关键字的用法,使用static关键字修饰的变量只有在第一次使用的时候才会被初始化,而且一个类里面static的成员变量只会有一份,这样就保证了无论多少个线程同时访问,所拿到的Resource对象都是同一个。
 
2.public class Singleton{
          private static Singleton instance=null;
          private Singleton(){}
          public static synchronized Singleton getInstance(){//synchronized修饰,表示同一时间只有一个线程能进入该方法
              if(instance==null)
                    instance=new Singleton();
               return instance; 
          }
第二种方法线程安全,但是锁粒度过大,运行效率低
 
3.public class Singleton(){
          private static Singleton instance=null;
          private Singleton(){}
          public static Singleton getInstance(){
               if(instance==null)
                    synchronized(Singleton.class)
                              {
                              if(instance==null)//判断两次空
                                   instance=new Singleton();
                    }
               return instance;
          }
}
第三种方法降低了锁的粒度,采用了双重锁检测的方式,但是由于指令重排的存在,所以非线程安全
 
有数据依赖性的两个操作不会被重排序,但是当这两个操作在不同的线城时,数据依赖性不被考虑
 
4.public  class Singleton{
          private static volatile Singleton instance=null;//用volatile来修饰
          private Singleton(){}
          public static Singleton getInstance(){
                    if(instance==null){
                              synchronized(Singleton.class){
                                       if(instance==null)
                                             instance=new Singleton(); 
                                   }
                         }
                    return instance;               
               }
}
第四种方法用volatile来修饰instance,volatile的作用:保证内存可见性,防止指令重排
 
5.public class InstanceFactory{
          private static class InstanceHolder{
                   public static Instance instance=new Instance(); 
               }
          public static getInstance(){
                   return InstanceFactory.InstanceHolder.instance; 
               }
          static Instance(){
              
               }
}
posted @ 2016-07-07 10:37  贴地  阅读(168)  评论(0)    收藏  举报