23种设计模式之单例模式

xiaoxiao2021-02-28  132

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

构造函数不对外开放,一般为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.

转载请注明原文地址: https://www.6miu.com/read-34662.html

最新回复(0)