设计模式-单例模式

来源:互联网 发布:极乐净土秀太捏脸数据 编辑:程序博客网 时间:2024/06/05 10:54

单例模式


定义

保证一个类仅有一个实例,并提供一个访问它的全局访问点。

应用场景

当需要保证类在虚拟机中的对象唯一性
创建多个实例浪费资源
多个实例由于多次调用而出现错误。
一般写工具类,线程池,缓存,数据库等可以使用

特点

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

设计思想

  • 将构造方法限定为private避免了类在外部被实例化。
  • 单例类中持有一个私有本类实例的引用。
  • 定义一个公共的方法getInstance(),在同一个虚拟机范围内,Singleton的唯一实例只能通过该方法访问。
  • 注意:事实上,通过Java反射机制是能够实例化构造方法为private的类的,那基本上会使所有的Java单例实现失效,此问题在此处不做讨论。

实现方式

一、懒汉式单例

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

  以上懒汉式单例的实现没有考虑线程安全问题,它是线程不安全的,并发环境下很可能出现多个Singleton实例。要实现线程安全,有以下三种方式,都是对getInstance这个方法改造,保证了懒汉式单例的线程安全。

1、在getInstance方法上加同步

public static synchronized Singleton getInstance() {      if (single == null) {            single = new Singleton();      }        return single;  }  

2、双重检查锁定

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

3、静态内部类

public class Singleton {    private Singleton (){}        public static final Singleton getInstance() {           return LazyHolder.INSTANCE;        }    // 静态内部类    private static class LazyHolder {           private static final Singleton INSTANCE = new Singleton();     }} 

  和饿汉式类似,两者都是通过类装载机制来保证初始化实例的时候只有一个线程,从而避免线程安全问题。饿汉式的Singleton类被加载,就会实例化Singleton,而静态内部类这种,当Singleton类被加载时,不会立即实例化,调用getInstance方法,才会装载SingletonHolder类,从而完成Singleton的实例化。

二、饿汉式单例

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

  饿汉式在类加载的同时就已经实例化一个静态的对象供系统使用,所以天生是线程安全的。但是若没有使用到该实例,依然会加载,从而造成资源浪费。

三、枚举实现单例模式

public enum SingletonEnum {    INSTANCE;    private Singleton instance;    SingletonEnum() {         instance = new Singleton()    }    public Singleton getInstance() {        return instance;    }}

  访问方式:SingletonEnum.INSTANCE.method();
  INSTANCE即为SingletonEnum类型的引用,得到它就可以调用枚举中的方法。既避免了线程安全问题,还能防止反序列化重新创建新的对象,但是失去了类的一些特性,没有延时加载,推荐使用。

四、使用容器实现单例模式

public class SingletonManager {    private static Map<String,Object> objMap = new HashMap<String,Object>();    private Singleton() { }    public static void registerService(String key,Object instance) {        if(!objMap.containsKey(key)) {            objMap.put(key,instance);        }    }    public static Object getService(String key) {        return objMap.get(key);    }}

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

优缺点
优点:保持类对象唯一性,对于频繁创建和销毁的对象可以提高性能。
缺点:扩展困难,单例的方法无法生成子类对象,要扩展的话基本要重写这个类。

原创粉丝点击