单例模式

使用模式最好的方式是:“把模式装进脑子里,然后在你的设计和已有的应用中,寻找何处可以使用它们。”

    1. 使用场景: 
      a. 产生莫对象会消耗过多的资源,为避免频繁的创建和销毁对象对资源造成的浪费。例如:

      对数据库的操作、访问IO、线程池、网络请求等。

      b. 某种类型的对象应该有且只有一个。若制造出多个这样的实例,可能导致:程序行为异常、资源使用过量、结果不一致等问题。如果多人能同时操作一个文件,又不进行版本管理,必然会有的修改被覆盖,所以:

      一个系统只能有:一个窗口管理器或文件系统,计时工具或 ID(序号)生成器,缓存(cache),处理偏好设置和注册表(registry)的对象,日志对象。

    2. 优点:减少系统开支、减少系统性能开销、避免对资源的多重占用和同时操作。
    3. 缺点:扩展困难、易引发内存泄漏、测试困难、一定程度上违背单一职责原则,进程被杀时可能有状态不一致的问题。
    4. 实现方式: 
      按加载时机分为饿汉模式和懒汉模式 
      按实现方式分为双重检查加锁、内部类和枚举方式等
    5. 定义: 
      构造函数对其他类不可见,仅仅提供一个获取唯一实例的静态方法,并且必须保证这个获取实例的方法时线程安全的,并防止反序列化、反射、克隆、多个类加载器、分布式系统等多种情况下重新生成新的实例对象。
    6. 具体实现方案: 
      懒汉模式 
      双重检测锁定方式:

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;
    }
}      

      该方式在1.5以下会失效。

      静态内部类:

public class Singleton {
    private Singleton(){}
    public static final Singleton getInstance(){
        return SingletonHolder.INSTANCE;
    }
    public static class SingletonHolder{
        private static final Singleton INSTANCE=new Singleton();
    }
}

      饿汉模式

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

饿汉与懒汉的比较: 
饿汉在类加载时就已经实例化了静态对象,所以第一次调用时更快,但是在程序运行期间会一直占据一定的内存;懒汉是延时加载,优势在于资源利用率高哦,但第一次调用时的初始化工作会导致性能延时,并且在后面每次获取实例时也要先判断实例是否被初始化,造成效率损耗。

登记式单例 
在我们的程序中,随着迭代版本的增加,代码也越来越复杂,往往会使用到多个处理不同业务的单例,这时我们就可以采用 Map 容器来统一管理这些单例,使用时通过统一的接口来获取某个单例。在程序的初始,我们将一组单例类型注入到一个统一的管理类中来维护,即将这些实例存放在一个 Map 登记薄中,在使用时则根据 key 来获取对象对应类型的单例对象。对于已经登记过的实例,从 Map 直接返回实例;对于没有登记的,则先登记再返回。从而在对用户隐藏具体实现、降低代码耦合度的同时,也降低了用户的使用成本。

public class SingletonManager {
    private static Map<String,Object> objectMap=new HashMap<>();
    private SingletonManager(){}
    public 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);
    }
}
原文地址:https://www.cnblogs.com/libertycode/p/6586902.html