Java双重校验锁单例原理

 更新时间:2022年01月21日 11:00:31   作者:让开,我要吃人了  
大家好,本篇文章主要讲的是Java双重校验锁单例原理,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下

前言

作为开发者,单例这个就再也熟悉不过了,但是作为多种单例实现模式,我个人觉得双重校验锁是非常不多的实现,我们简单来分析一下其原理。

正文

先来说一下Java版本的,后面会涉及Kotlin中的代码我们再做比对。

代码实现

Java代码实现如下:

//双重校验锁单例
public class SingleInstance {
    //必须volatile修饰 见分析1
    private volatile static SingleInstance instance;
    //私有化构造函数
    private SingleInstance() {
    }
 
    public static SingleInstance getInstance() {
        //第一个判空 见分析2
        if (instance == null) {
            synchronized (SingleInstance.class) {
                //第二个判空 见分析3
                if (instance == null) {
                    //新建实例
                    instance = new SingleInstance();
                }
            }
        }
        return instance;
    }
}

首先这里synchronized关键字没有修饰整个getInstance函数,因为这个函数可能使用地方很多,这样就会造成其他线程阻塞,不太好,所以这里只同步了一段代码。

分析2:为什么在进入同步代码块时需要进行进行判空,假如有线程A和线程B,这时线程A先判断instance为null,所以它进入了同步代码块,创建了对象,然后线程B再进来时,它就不必再进入同步代码快了,可以直接返回,也其实也就是懒加载,可以加快执行速度。

分析3:为什么在同步代码块中还要再进行一次判断呢,假如有线程A和线程B,它俩A先调用方法,B紧接着调用,这时A、B在分析2出的判空都是空,所以A进入同步代码块,B进行等待,当A进入同步代码块中创建了对象后,A线程释放了锁,这时B再进入,如果这时不加分析3的判空,B又会创建一个实例,这明显不符合规矩。

分析1:那既然加了2层判断,那为什么还要加个volatile关键字呢,这里知识点就有点多了。

因为新建实例的代码:

instance = new SingleInstance();

它不是一个原子操作,这个简单的赋值可以分为3步:

1、给SingleInstance分配内存

2、调用SingleInstance的构造方法

3、把instance指向分配的内存空间

这是正常逻辑的3个步骤,也只有按1 2 3执行后,这个instance才不是null。

但是Java内存模型允许这个进行指令重排序,也就是这3步可能是123也可能是132,所以这里就有问题了。

假如线程A和线程B,线程A已经跑到分析3处的代码,这时这条指令执行是132,刚把步骤3执行完,这时线程B跑到了分析1处的代码,会发现instance不为null了,这时线程B就直接返回了,从而导致错误。

既然知道了原因,那volatile关键字就是解决这个的,它可以禁止指令重新排序,而且保证所有线程看到这个变量是一致的,也就是不会从缓存中读取(这个特性后面有机会再说),所以在创建instance实例时,它的步骤都是123,就不会出错了。

总结

到此这篇关于Java双重校验锁单例原理的文章就介绍到这了,更多相关Java校验锁单例内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 一篇文章带你搞懂Java restful 接口开发

    一篇文章带你搞懂Java restful 接口开发

    这篇文章主要介绍了Java restful 接口开发的几种方式(HTTPS),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2021-10-10
  • java如何读取某个文件夹中的全部文件(包括子文件夹)

    java如何读取某个文件夹中的全部文件(包括子文件夹)

    这篇文章主要介绍了java如何读取某个文件夹中的全部文件(包括子文件夹),具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-12-12
  • 详解Java数组的定义和声明方法

    详解Java数组的定义和声明方法

    在Java开发中,数组是最常用的数据结构之一,因此,深入了解Java数组的定义和声明是非常必要的,本文将详细介绍Java数组的定义和声明方法,以及其在实际开发中的应用场景、优缺点等方面,需要的朋友可以参考下
    2023-11-11
  • 详解Java 虚拟机垃圾收集机制

    详解Java 虚拟机垃圾收集机制

    这篇文章主要介绍了Java 虚拟机垃圾收集机制的相关资料,帮助大家更好的理解和学习Java虚拟机的相关知识,感兴趣的朋友可以了解下
    2020-12-12
  • springboot如何将http转https

    springboot如何将http转https

    这篇文章主要介绍了springboot如何将http转https,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-04-04
  • SpringBoot @PostConstruct和@PreDestroy的使用说明

    SpringBoot @PostConstruct和@PreDestroy的使用说明

    这篇文章主要介绍了SpringBoot @PostConstruct和@PreDestroy的使用说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-09-09
  • java生成excel并导出到对应位置的方式

    java生成excel并导出到对应位置的方式

    这篇文章主要介绍了java生成excel并导出到对应位置的方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-01-01
  • SpringBoot整合Swagger和Actuator的使用教程详解

    SpringBoot整合Swagger和Actuator的使用教程详解

    Swagger 是一套基于 OpenAPI 规范构建的开源工具,可以帮助我们设计、构建、记录以及使用 Rest API。本篇文章主要介绍的是SpringBoot整合Swagger(API文档生成框架)和SpringBoot整合Actuator(项目监控)使用教程。感兴趣的朋友一起看看吧
    2019-06-06
  • 使用ServletInputStream()输入流读取图片方式

    使用ServletInputStream()输入流读取图片方式

    这篇文章主要介绍了使用ServletInputStream()输入流读取图片方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-10-10
  • java实现合并2个文件中的内容到新文件中

    java实现合并2个文件中的内容到新文件中

    这篇文章主要介绍了java实现合并2个文件中的内容到新文件中,思路非常不错,这里推荐给大家。
    2015-03-03

最新评论