java单例模式的最佳实现!

前言

大致的了解了一下单例模式的实现,经供参考!

常见实现(懒汉和饿汉)

懒汉式单例模式
/**
 * 懒汉式,先不创建实例,等到需要时在创建。
 * 多线程情况下并发效率低。
 * 结论:线程安全,调用效率不高,但是可以延时加载。
 */
public class LazySingleton {
    /**
     * 静态实例变量
     */
    private static LazySingleton instance;

    /**
     * 私有构造函数
     */
    private LazySingleton() {
    }

    /**
     *懒汉式创建实例,需要同步处理
     * @return
     */
    public static synchronized LazySingleton getInstance(){
        if (instance == null){
            instance = new LazySingleton();
        }
        return instance;
    }
}

懒汉式单例模式实现结论:线程安全,调用效率不高,但是可以延时加载。

饿汉式单例模式
/**
 * 饿汉式,类初始化时立即加载这个对象,
 * 如果加载这个对象耗时间长并且这个对象没有被使用,得不偿失。
 * 结论:线程安全,调用效率高,但是不是延时加载。
 */
public class HungrySingleton {
    /**
     * 静态实例对象
     */
    private static HungrySingleton instance = new HungrySingleton();

    /**
     * 私有的构造函数
     */
    private HungrySingleton() {
    }
    
    /**
     * 静态方法并不需要做同步处理
     * @return
     */
    public static HungrySingleton getInstance(){
        return instance;
    }
    
}

饿汉式单例模式实现结论:线程安全,调用效率高,但是不是延时加载。

进阶实现

静态内部类实现单例模式(推荐)
/**
 * 静态内部类实现单例模式(懒加载的一种)
 * 静态内部类只有在调用的时候才初始化,并且初始化过程线程安全。
 * instance不提供修改实例方法,静态变量只初始化一次,所以final修饰不加也一样。
 * 兼备了并发高效调用和懒加载的优势。
 * 结论:线程安全,调用效率高,并且可以延时加载。
 */
public class StaticClassSingleton {
    //私有构造函数
    private StaticClassSingleton(){};

    //静态内部类
    private static class SingletonClassInstance{
        private static final StaticClassSingleton INSTANCE =
                new StaticClassSingleton();
    }

    //提供实例的调用方法
    public static StaticClassSingleton getInstance(){
        return SingletonClassInstance.INSTANCE;
    }
}

静态内部类实现单例模式结论:线程安全,调用效率高,并且可以延时加载。

枚举实现单例模式 (推荐)
/**
 * 枚举类对象本身就是一个单例对象。
 * 没有延时加载的特性。
 * 可以天然的防止反射和反序列化的漏洞,因为枚举是基于JVM底层实现的。
 * 结论:线程安全,调用效率高,但是不是延时加载,天然防止反射和反序列化漏洞。
 */
public enum  EnumSingleton {
    /**
     * 枚举对象
     */
    INSTANCE;

    /**
     * 成员方法
     */
    public void singletonOperation(){
        //单例对象的其它操作实现。
    }
}

枚举实现单例模式结论:线程安全,调用效率高,但是不是延时加载,天然防止反射和反序列化漏洞。

其它实现

基于双重检测得单例模式(不推荐)
/**
 * 懒汉式实现的一种
 * 但是由于编译器优化的原因和JVM底层内部模型原因,偶尔会出现问题
 * 结论:不建议使用。
 */
public class DoubleCheckLocking {
    /**
     * 懒汉式,加上volatile,因为线程创建对象有三步
     * 1、new开辟空间 //2、构造 初始化对象信息 //3、返回对象的地址给引用
     * volatile防止指令重排序,导致2步骤没执行完3步骤便返回的引用。
     */
    private static volatile DoubleCheckLocking instance;
    
    /**
     * 私有的构造函数
     */
    private DoubleCheckLocking(){
    }
    
    /**
     * 双重检测的单例模式
     * @return
     */
    public static DoubleCheckLocking getInstance() {
        //非空返回,不走同步块,提高效率
        if (null == instance) {
            synchronized (DoubleCheckLocking.class) {
                if (null == instance) {
                    instance = new DoubleCheckLocking();
                }
            }
        }
        return instance;
    }
}

如何选择

单例的使用比如网站计数器,日志文件的操作。大概使用场景分为如下:

  • 实例创建占用资源多,耗时多,需要延时加载。
    使用静态内部类实现单例模式(推荐)或懒汉式
  • 实例创建占用资源少,耗时少,即不需要延时加载。
    使用枚举实现单例模式(推荐)或饿汉式

结束

内容仅供参考,如有错误请帮忙指正,欢迎补充。

你可能感兴趣的:(Java)