单例模式

来源:互联网 发布:淘宝开店审核要多久 编辑:程序博客网 时间:2024/06/08 06:17

特点

  1. 单例类只能有一个实例。
  2. 单例类必须自己创建自己的唯一实例。
  3. 单例类必须给所有其他对象提供这一实例。

单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。这些应用都或多或少具有资源管理器的功能。每台计算机可以有若干个打印机,但只能有一个Printer Spooler,以避免两个打印作业同时输出到打印机中。每台计算机可以有若干通信端口,系统应当集中管理这些通信端口,以避免一个通信端口同时被两个请求同时调用。总之,选择单例模式就是为了避免不一致状态,避免政出多头

分类

  • 饿汉式:线程安全
//饿汉式单例类.在类初始化时,已经自行实例化   public class Singleton1 {      private Singleton1() {}      private static final Singleton1 single = new Singleton1();      //静态工厂方法       public static Singleton1 getInstance() {          return single;      }  }  
  • 懒汉模式(线程不安全)
//懒汉式单例类.在第一次调用的时候实例化自己   public class Singleton {      private Singleton() {}      private static Singleton single=null;      //静态工厂方法       public static Singleton getInstance() {           if (single == null) {                 single = new Singleton();           }            return single;      }  }  

加锁:使用在方法上加synchronized 或者使用关键字volatile加锁

//在方法上加synchronized public static synchronized Singleton getInstance() {           if (single == null) {                 single = new Singleton();           }            return single;  }  //双重检查锁定public class Singleton {        private volatile static Singleton singleton;        private Singleton (){      }         public static Singleton getInstance() {        if (instance== null) {            synchronized (Singleton.class) {            if (instance== null) {                instance= new Singleton();            }           }       }       return singleton;       }   } 
  • 静态内部类单例模式(推荐使用)
 public class Singleton {     private Singleton(){    }      public static Singleton getInstance(){          return SingletonHolder.sInstance;      }      private static class SingletonHolder {          private static final Singleton sInstance = new Singleton();      }  } 

第一次加载Singleton类时并不会初始化sInstance,只有第一次调用getInstance方法时虚拟机加载SingletonHolder 并初始化sInstance ,这样不仅能确保线程安全也能保证Singleton类的唯一性,所以推荐使用静态内部类单例模式。

注意(避免被反序列化)

反序列化操作提供了readResolve方法,这个方法可以让开发人员控制对象的反序列化。在上述的几个方法示例中如果要杜绝单例对象被反序列化是重新生成对象,就必须加入如下方法:

//重写方法返回实例避免反序列化private Object readResolve() throws ObjectStreamException{return singleton;}
  • 登记式单例(使用容器实现单例模式)
public class SingletonManager {   private static Map<String, Object> objMap = new HashMap<String,Object>();  private Singleton() {   }  public static void registerService(String key, Objectinstance) {    if (!objMap.containsKey(key) ) {      objMap.put(key, instance) ;    }  }  public static ObjectgetService(String key) {    return objMap.get(key) ;  }}

用SingletonManager 将多种的单例类统一管理,在使用时根据key获取对象对应类型的对象。这种方式使得我们可以管理多种类型的单例,并且在使用时可以通过统一的接口进行获取操作,降低了用户的使用成本,也对用户隐藏了具体实现,降低了耦合度

0 0