设计模式之单例模式

来源:互联网 发布:伊尔18客机数据 编辑:程序博客网 时间:2024/06/05 06:02

1. 什么是单例模式

  1. 该类只能有一个实例;
  2. 该类能够自动实例化;
  3. 对整个系统可见,即必须向整个系统提供这个实例。

2. 实现

a. 饿汉式

public class Singleton {      private static Singleton instance=new Singleton();      private Singleton(){      }      public static Singleton getInstance(){          return instance;      }  }  

实现简单,基于classloder机制避免了多线程的同步问题,不过,instance在类装载时就实例化,没有进行延迟加载。

b. 懒汉

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

lazy loading很明显,但是在多线程时不能正常工作

c. 懒汉 + 同步方法

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

解决了多线程同步,但同步范围太大,在实例化instacne后,获取实例仍然是同步的,效率低

d. 懒汉 + 同步块

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

缩小了同步范围,但存在创建多个实例的可能,比如线程A和B同时执行到了synchronized(Singleton.class),线程B获得锁执行完之后,线程A获得锁,但是此时没有检查singleton是否为空就直接执行了,所以还会出现两个singleton实例的情况

e. 懒汉 + 双重检查(DCL)

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

instance=new Singleton()并不是原子语句,实际包括了下面三大步骤:
1. 为对象分配内存
2. 初始化实例对象
3. 把引用instance指向分配的内存空间

处理器会进行指令重排序优化,当重排后执行顺序为1,3,2时,若线程1执行到3,此时线程2判断instance!=null,直接返回instance引用,但实际上实例对象还没有初始化完毕,使用它可能会造成程序崩溃。

e. 懒汉 + 双重检查 + volatile

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

使用volatile提供内存屏障,限制处理器进行指令优化重排,保证了instance赋值操作是最后一步完成,不会再出现instance在对象没有初始化时就不为null的情况

f. 懒汉+静态内部类

public class Singleton{      private Singleton(){      }      public static  Singleton getInstance(){          return InstanceHolder.instance;      }      static class InstanceHolder{          private static Singleton instance = new Singleton();      }  }  

静态内部类在Singleton类被装载时并不会立即实例化,而是在调用getInstance方法,才会装载SingletonInstance类,从而完成Singleton的实例化。
类的静态属性只会在第一次加载类的时候初始化,所以在这里,JVM帮助我们保证了线程的安全性,在类进行初始化时,别的线程是无法进入的。

g. 枚举

public enum EasySingleton {      INSTANCE;  }  

借助JDK1.5中添加的枚举来实现单例模式。不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象。

原创粉丝点击