剑指Offer题目2:实现 Singleton 模式(Java)

栏目: 后端 · 发布时间: 5年前

内容简介:关于 volatile 指令重排序的分析,详见以下文章:剑指Offer 说 double check 方法有点复杂容易出错实在有点牵强。
/**
 * 多线程高效单例 Double Check
 * @Author: hebin.yang
 * @CreateDate: 2019-06-30 11:35
 */
public class Ex2Singleton3 {

    private static Ex2Singleton3 instance;

    private Ex2Singleton3() {}

    /**
     * Double Check
     * 分析:由于 synchronized 关键字可以确保在释放锁之前,将数据刷新到主内存中,线程2 可以读取到最新的值
     * 从而确保不会重复创建对象。
     * 缺陷:无序性
     * new 一个对象分两步,而且是无序的。
     * @return
     */
    public static Ex2Singleton3 getInstance() {
        if (instance == null) {
            synchronized (Ex2Singleton3.class) {
                if (instance == null) {
                    instance = new Ex2Singleton3();
                }
            }
        }
        return instance;
    }
}
复制代码

2、安全版 Double Check 单例

/**
 * 安全版 Double Check 单例模式
 * @Author: hebin.yang
 * @CreateDate: 2019-06-30 16:02
 */
public class Ex2Singleton4 {

    /**
     * 增加 volatile 修饰,禁止创建对象指令重排序,修复多线程下由于指令重 排序 导致的异常
     */
    private static volatile Ex2Singleton4 instance;
    
    private Ex2Singleton4() {}
    
    public static Ex2Singleton4 getInstance() {
        if (instance == null) {
            synchronized (Ex2Singleton4.class) {
                if (instance ==  null) {
                    instance = new Ex2Singleton4();
                }
            }
        }
        return instance;
    }
}
复制代码

关于 volatile 指令重排序的分析,详见以下文章:

Double check 为何需要 volatile?

剑指Offer 说 double check 方法有点复杂容易出错实在有点牵强。

3、利用静态内部类初始化单例

特性:利用在 Java 中,静态内部类只会在第一次调用到时进行初始化的特性,实现单例模式。

/**
 * 静态内部类单例模式
 * @Author: hebin.yang
 * @CreateDate: 2019-06-30 16:33
 */
public class Ex2Singleton5 {

    static class SingletonHolder {
        private static Ex2Singleton5 INSTANCE = new Ex2Singleton5();
    }

    private Ex2Singleton5() {}

    public static Ex2Singleton5 getInstance() {
        return SingletonHolder.INSTANCE;
    }
}
复制代码

分析:当Ex2Singleton5 加载时,并不会实例化静态内部类,只有当第一次调用静态内部类的 INSTANCE 时,才会加载 SingletonHolder,从而实例化 Ex2Singleton5 这个单例的对象。

优势:由于这种场景下单例对象的实例化,是在完成静态内部类加载时完成的,所以天生对多线程友好。getInstance() 也不需要关键字来同步。

优点:延迟加载,无需增加同步关键字(减少性能损耗)。

静态内部类又是如何实现线程安全的呢?

原理

由于静态内部类加载时只会执行一次类初始化方法 <clinit>() ,JVM 对该方法加了锁,确保当多个线程同时试图去执行类的初始化方法 <clinit>() 时,只有一个线程能执行,其余线程阻塞。并且,确保该方法只被执行一次。

所以实现了线程安全。

总结:一个静态内部类被加载初始化时,从类加载器的角度来看,是线程安全的,而单例对象 INSTANCE 在这个静态内部类中是一个静态 Field,所以它跟随这个静态内部类的加载而初始化,且只在类加载时初始化一次。

详细分析可参考:《类加载时机汇总》


以上所述就是小编给大家介绍的《剑指Offer题目2:实现 Singleton 模式(Java)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

转型之战

转型之战

吴晓波 / 2015-7-1

互联网时代大潮席卷而来,互联网究竟是“魔法手杖”,还是“效率金箍棒”?传统企业如何正确借助和利用互联网思维帮助自身转变思维、完成企业转型升级?本书分两篇,上篇为传统行业互联网转型极具代表性和借鉴意义的案例,下篇精选吴晓波转型大课的独 家内容,梳理了吴晓波、刘伟、刘润、金霞、刘博、赵峰、张蕴蓝、张荣耀、李嘉聪、曾玉波等各行业10位导师关于互联网思维的精华理念和观点,其中囊括各传统行业互联网转型成功的......一起来看看 《转型之战》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

SHA 加密
SHA 加密

SHA 加密工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具