单例模式

定义:确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。

单例模式的七种实现方式:

1.饿汉式

public class SingleInstance {

    private static SingleInstance mInstance = new SingleInstance();
    
    private SingleInstance() {}
    
    public static SingleInstance getInstance() {
        return mInstance;
    }
}

2.懒汉式--线程不安全

public class SingleInstance {

    private static SingleInstance mInstance;
    
    private SingleInstance() {}
    
    public static SingleInstance getInstance() {
        if (mInstance == null) {
            mInstance = new SingleInstance();
        }
        return mInstance;
    }
}

3.懒汉式--线程安全

public class SingleInstance {

    private static SingleInstance mInstance;
    
    private SingleInstance() {}
    
    public static synchronized SingleInstance getInstance() {
        if (mInstance == null) {
            mInstance = new SingleInstance();
        }
        return mInstance;
    }
}

优点:懒汉式的优点是只有在使用时才会被实例化,在一定程度上节约了资源;
缺点:每次调用getInstance()都要同步,造成不必要的同步开销;

4.Double Check Lock(DCL)双重校验锁,线程安全

public class SingleInstance {

    private static SingleInstance mInstance;
    
    private SingleInstance() {}
    
    public static SingleInstance getInstance() {
        if (mInstance == null) {
            synchronized (SingleInstance.class) {
                if (mInstance == null) {
                    mInstance = new SingleInstance();
                }
            }
        }
        return mInstance;
    }
}

getInstance()方法中对mInstance进行了两次判空:
第一层判断主要是为了避免不必要的同步;
第二层判断是为了在null的情况下创建实例;
优点:资源利用率高,第一次执行getInstance()的单例对象才会被实例化,效率高;
缺点:第一次加载反应稍慢,由于Java内存模型的原因偶尔会失败。在高并发环境下也有一定的缺陷,虽然发生的概率很小;

5.使用静态内部类的方式

public class SingleInstance {

    private SingleInstance() {}
    
    /**
     * 静态内部类
     */
    private static class SingleInstanceHolder {
        private static SingleInstance mInstance = new SingleInstance();
    }
    
    public static SingleInstance getInstance() {
        return SingleInstanceHolder.mInstance;
    }
}

当第一次加载SingleInstance类时不会初始化mInstance,只有在第一次调用SingleInstancegetInstance()方法时才会导致mInstance被初始化。因此,第一次调用getInstance()方法会导致虚拟机加载SingleInstanceHolder类,这种方式不仅能保证线程安全,也能够保证单例对象的唯一性,同时也延迟了单例的实例化。

6.枚举单例

public enum SingleEnum {
    
    INSTANCE;
    
    public void doSomething() {
        System.out.println("do somth");
    }
}

在上述几种单例的实现方式中,如果将对象实例进行序列化,就会出现重新创建对象实例的情况。而对应枚举不会存在这个问题,因为即使反序列化它也不会重新生成新的实例。

7.使用容器实现单例模式

public class SingleManager {

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

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

你可能感兴趣的:(单例模式)