Java并发编程中的volatile关键字详解

 更新时间:2023年08月14日 08:29:24   作者:刘婉晴  
这篇文章主要介绍了Java并发编程中的volatile关键字详解,volatile 用于保证我们某个变量的可见性,使其一直存放在主存中,不被移动到某个线程的私有工作内存中,需要的朋友可以参考下

一、什么是 JMM

JMM 是 Java 内存模型的缩写,其将 Java 运行的底层内存模型抽象成了 主存 和 工作内存。

其中, 主存就是线程共享的内存, 工作内存就是线程所私有的内存 。

二、什么是可见性

可见性是指放在主存中的内容所有线程都是可见的 。

但是由于 JIT (即时编译器)的存在,有时我们放在主存中内容,会被其移动到工作内存给某个线程私有 。

三、引出 volitale

1. volatile 用来做什么

volatile 用于保证我们某个变量的可见性,使其一直存放在主存中,不被移动到某个线程的私有工作内存中。

synchronized 也能实现可见性,但是麻烦,没有 volatile 简洁,而且更加重量级,会降低效率

2. 举个例子,怎么使用

volatile 可以用来修饰 :

  • 成员变量
  • 静态成员变量

使用实例

public class TestVolatile {
     volatile static boolean use = true;
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            while (use){
                // 执行相应操作
            }
        });
        thread.start();
        // 主线程休眠一秒
        sleep(1000);
        use = false;
    }
}

3. volatile 可以保证原子性嘛

不能,它只能保证可见性,不能保证原子性 。

四、 volatile 原理 (JDK 1.5 之后)

内存屏障技术, Memory Barrier

  • 写指令,加入写屏障
  • 读指令,加入读屏障

1. 保证可见性

  • 写屏障保证在该屏障之前,对共享变量的改动,都同步到主存中
  • 读屏障保证在该屏障之后,对共享变量的读取,加载的是主存中的最新数据

在这里插入图片描述

2. 保证有序性

  • 写屏障确保指令重排时,不会将写屏障之前的代码排在写屏障之后
  • 读屏障确保指令重排时,不能将读屏障之前的代码排在读屏障之后

3. 解决 dcl 问题 (double-checked locking)

public class Singleton {
    private Singleton() {}
    private static Singleton INSTANCE = null;
    public static Singleton getINSTANCE(){
        if(INSTANCE == null){
            synchronized (Singleton.class) {
                if(INSTANCE == null) {
                	// 会因为指令重排序出现问题
                    INSTANCE = new Singleton();
                }
            }
        }
        return INSTANCE;
    }
}

解决 dcl 问题

为共享变量加上 volatile 关键字,从而避免指令重排序的问题 。 (jvm 可能对指令进行重排序,重排序可以会在多线程并发时出现问题)

在这里插入图片描述

到此这篇关于Java并发编程中的volatile关键字详解的文章就介绍到这了,更多相关Java中的volitale关键字内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Springboot使用Redis中ZSetOperations实现博客访问量

    Springboot使用Redis中ZSetOperations实现博客访问量

    在日常的网站使用中,经常会碰到页面的访问量,本文主要介绍了Springboot使用Redis中ZSetOperations实现博客访问量,具有一定的参考价值,感兴趣的可以了解一下
    2024-01-01
  • SpringMVC拦截器——实现登录验证拦截器的示例代码

    SpringMVC拦截器——实现登录验证拦截器的示例代码

    本篇文章主要介绍了SpringMVC拦截器——实现登录验证拦截器的示例代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。
    2017-02-02
  • SpringBoot项目多层级多环境yml设计详解

    SpringBoot项目多层级多环境yml设计详解

    这篇文章主要为大家介绍了SpringBoot项目多层级多环境yml设计详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-03-03
  • SpringMVC基于配置的异常处理器

    SpringMVC基于配置的异常处理器

    这篇文章主要为大家介绍了SpringMVC基于配置的异常处理器,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-05-05
  • java中MultipartFile类型转为File类型的4种方法

    java中MultipartFile类型转为File类型的4种方法

    Spring提供了一个MultipartFile接口来处理文件上传,但有时候我们需要将MultipartFile转换为File来进行一些特定的操作,比如保存文件到本地或者进行文件的处理等,这篇文章主要给大家介绍了关于java中MultipartFile类型转为File类型的4种方法,需要的朋友可以参考下
    2024-09-09
  • Reactive Programming入门概念详解

    Reactive Programming入门概念详解

    这篇文章主要为大家介绍了Reactive Programming入门概念详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-09-09
  • application作用域实现用户登录挤掉之前登录用户代码

    application作用域实现用户登录挤掉之前登录用户代码

    这篇文章主要介绍了application作用域实现用户登录挤掉之前登录用户代码,具有一定参考价值,需要的朋友可以了解下。
    2017-11-11
  • Java并发编程示例(七):守护线程的创建和运行

    Java并发编程示例(七):守护线程的创建和运行

    这篇文章主要介绍了Java并发编程示例(七):守护线程的创建和运行,在本节示例中,我们将创建两个线程,一个是普通线程,向队列中写入事件,另外一个是守护线程,清除队列中的事件,需要的朋友可以参考下
    2014-12-12
  • java web实现邮箱发送功能

    java web实现邮箱发送功能

    这篇文章主要为大家详细介绍了java web实现邮箱发送功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-05-05
  • Java Stream reduce()使用指南

    Java Stream reduce()使用指南

    reduce()是Java Stream API中的一个重要终端操作,用于将流中的元素通过二元运算符结合起来,生成单一结果,它主要用于计算总和、乘积、最大值、最小值和字符串连接等,本文给大家介绍Java Stream reduce(),感兴趣的朋友一起看看吧
    2024-10-10

最新评论