23种设计模式之单例模式

来源:互联网 发布:华盛顿和李大学知乎 编辑:程序博客网 时间:2024/06/10 17:29

定义:确保一个类中只有一个实例,而且自行实例化并向整个系统提供这个实例。或者说某种类型的对象有且只有一个。
实现单例模式主要有以下几个关键点:

  • 构造函数不对外开放,一般为Private
  • 通过一个静态方法或者枚举返回单例类对象
  • 确保单例类的对象有且只有一个,尤其是在多线程环境下
  • 确保单例类对象在反序列化时不会被重新构建对象。

单例的实现方式有多重:饿汉式,懒汉式,静态内部类,双重校验锁(DCL),枚举等,推荐使用静态内部类和双重校验锁。
1.饿汉式:

/** * Created by jmfstart on 2017/5/5. * 饿汉式 */public class Singleton {    private static final Singleton singleton = new Singleton();    private Singleton() {    }    public static Singleton getInstance() {        return singleton;    }}

这种方式基于类加载机制避免了多线程的同步问题,不过,instance在类装载时就实例化,虽然导致类装载的原因有很多种,在单例模式中大多数都是调用getInstance方法, 但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化instance显然没有达到懒加载的效果。
2.懒汉式(线程不安全的)

/** * Created by jmfstart on 2017/5/5. * 懒汉式 */public class Singleton {    private static  Singleton singleton ;    private Singleton() {    }    public static Singleton getInstance() {        if(singleton == null) {            singleton = new Singleton();        }        return singleton;    }}

这种写法懒加载很明显,但是致命的是在多线程不安全。
3.懒汉式(线程安全的)

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

大家细想,假如对象已经被初始化instance,现在每次调用getInstance()方法时都会进行同步,这会消耗不必要的资源。不建议使用
4.Double Check Lock(DCL)实现单例

/** * Created by jmfstart on 2017/5/5. * DCL方式实现 */public class Singleton {    private static  Singleton singleton ;    private Singleton() {    }    public static Singleton getInstance() {        if(singleton == null) {            synchronized (Singleton.class){                if(singleton == null) {                    singleton = new Singleton();                }            }        }        return singleton;    }}

优点:资源利用率高。
缺点:第一次加载时反应稍慢。在高并发环境下也有一定的缺陷,虽然发生的概率很小。
DCL模式是使用最多的单例实现方式,它能够在需要时才实例化单例对象。这种方式一般能够满足需求。
5.静态内部类单例模式
DCL在某些情况下出现失效的问题,这个问题被称为双重检验锁(DCL)失效,建议使用静态内部类替代

/** * Created by jmfstart on 2017/5/5. * 静态内部类实现单例 */public class Singleton {    private Singleton() {    }    public static Singleton getInstance() {        return SingletonHolder.singleton;    }    //静态内部类    private static class SingletonHolder {        private static  Singleton singleton = new Singleton();     }}

这种方式不仅能够保证线程安全,也能够保证单例对象的唯一性,同时也延迟了单例的实例化,所以这是推荐使用的单例模式的实现方式。
6.枚举类实现单例

/** * Created by jmfstart on 2017/5/5. * 枚举实现单例 */public enum Singleton {    INSTANCE;    public void doSomething() {        System.out.println("do sth.");    }}

这种方式是Effective Java作者Josh Bloch 提倡的方式,它不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象,可谓是很坚强的壁垒啊,不过,个人认为由于1.5中才加入enum特性,用这种方式写不免让人感觉生疏,在实际工作中,我也很少看见有人这么写过。
7.使用容器实现单例模式
这种实现方式比较另类

/** * Created by jmfstart on 2017/5/5. * 单例的集合,便于管理 */public class SingletonManager {    private static Map<String,Object> objectMap = new HashMap<>();    private SingletonManager(){    }    private static void registerService(String key,Object instance){        if(objectMap.containsKey(key)) {            objectMap.put(key,instance);        }    }    public static Object getService(String key){        return objectMap.get(key);    }}

单例模式总结
优点
a.单例模式在内存中只有一个实例,减少内存开支,非常适合频繁的创建和销毁一个对象的场景
b.由于单例模式只生成一个实例,所以减少了系统的性能开支,使用永久驻留内存的方式来解决。
c.单例模式避免了对公共资源的多重占用。如读写文件操作等等。
d.单例模式可以在系统设置全局的访问点。
缺点
a.单例模式一般没有接口,扩展很困难,除了修改代码基本没有其他方法可以实现。
b.单例对象如果持有Context,那么很容易引起内存泄露,最好传递Application Context.

2 0
原创粉丝点击