Java中volatile关键字的线程的可见性、有序性详解

 更新时间:2024年01月11日 10:29:12   作者:好奇的7号  
这篇文章主要介绍了Java中volatile关键字的线程的可见性、有序性详解,在juc多线程并发编程中,常常需要关注线程的"可见性"与"有序性",本文将详细介绍这两部分内容,以及volatile关键字的使用,需要的朋友可以参考下

引言

在juc多线程并发编程中,常常需要关注线程的“可见性”与“有序性”。本文将详细介绍这两部分内容,以及volatile关键字的使用。

阅读本文前需要一些jvm运行时内存、进程与线程、共享内存、锁等相关知识。

1、可见性

1.1 定义

当一个对象在多个内存中都存在副本时,如果一个内存修改了共享变量,其它线程也应该能够看到被修改后的值。

1.2 解释

解释这句话,首先我们要知道,进程是操作系统分配资源的最小单位,在每个进程里,都包含有数据共享的区域(例如其中有成员变量、堆、静态常量等,详情查阅jvm运行时内存),并可能包含多个线程。 在jvm底层,每个线程想要操作某个共享变量时,不能够直接操作共享区域的“主存”,而是要先把数据从主存读到线程自己的高速缓存中,再进行操作,再赋值回去。

“具体来说,当一个线程要读取某个变量的值时,它首先检查自己的工作缓存中是否存在该变量的副本。 如果存在,则直接读取副本的值; 如果不存在,则从主内存中获取该变量的最新值,并将其复制到自己的工作缓存中。 类似地,当一个线程要修改某个变量的值时,它首先会在自己的工作缓存中修改副本,再根据一定的策略将变化同步回主内存。”

那么可见性的概念相应而来:多个线程都存了同一个对象副本,如果此时有一个内存修改了共享变量,其他的线程应该能够“看到”,而不是傻b一样仍旧拿着自己缓存里的值操作了。

1.3 实例说明

例如下面情况,如果main 线程对 run 变量的修改对于 t 线程不可见,导致了 t 线程无法停止:

其原因是t线程频繁从主内存中读取 run 的值,JIT 编译器会将 run 的值缓存至自己工作内存中的高速缓存中, 减少对主存中 run 的访问。 那么,当主线程(也就是其他线程)把run变为false,由于子线程t(当前线程)仍然从高速缓存里读的run,会认为run并没有改变,从而逻辑出现问题。

1.4 解决方法:volatile(易变关键字)

作用:volatile可以用来修饰成员变量和静态成员变量,他可以避免线程从自己的工作缓存中查找变量的值,必须到主存中获取它的值。(关键点)

然而volatile并不能保证原子性,例如不加锁的多线程执行函数,对成员变量i进行i++ i--,最后得到的结果i不一定是不变的。 因为volatile关键字,只能让该线程在使用数据前强制从主存读取,但读取后是否发生改变是看不见的。如果有别的线程在该线程读取后成功改变了共享内存的值,还是会发生指令交错。

2、有序性

在多线程环境下,由于编译器和处理器对指令进行优化和重排序,可能会导致操作的执行顺序发生改变,从而违反了代码编写的原始顺序。

为了保证有序性,可以使用以下方法:

使用volatile关键字:对关键的共享变量使用volatile关键字进行声明,以确保对该变量的写操作立即对其他线程可见。

使用synchronized关键字或Lock机制:通过使用同步块或锁来保护共享资源的读写操作,确保线程之间的有序访问。

使用原子类:Java提供了一些原子类(如AtomicInteger、AtomicLong等)来进行原子操作,这些原子类的方法能够保证操作的原子性、可见性和有序性。

简单来说volatile避免了指令重排,也就避免了多线程中可能产生的问题。

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

相关文章

  • 如何使用Java实现指定概率的抽奖

    如何使用Java实现指定概率的抽奖

    这篇文章主要给大家介绍了关于如何使用Java实现指定概率的抽奖的相关资料,Java抽奖程序的基本原理是通过随机数生成器来实现随机抽奖的功能,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-07-07
  • 深入理解 Java注解及实例

    深入理解 Java注解及实例

    这篇文章主要介绍了深入理解 Java注解及实例的相关资料,希望通过本文大家能够掌握java注解的知识,需要的朋友可以参考下
    2017-09-09
  • MyBatis详细执行流程的全纪录

    MyBatis详细执行流程的全纪录

    这篇文章主要给大家介绍了关于MyBatis详细执行流程的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-04-04
  • springboot 配置使用swagger2操作

    springboot 配置使用swagger2操作

    这篇文章主要介绍了springboot 配置使用swagger2操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-10-10
  • JVM垃圾回收原理解析

    JVM垃圾回收原理解析

    这篇文章主要介绍了JVM垃圾回收原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-08-08
  • Java和C#下的参数验证方法

    Java和C#下的参数验证方法

    下面小编就为大家带来一篇Java和C#下的参数验证实现方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-09-09
  • SpringBoot整合freemarker实现代码生成器

    SpringBoot整合freemarker实现代码生成器

    这篇文章主要为大家详细介绍了SpringBoot如何整合freemarker实现一个简单的代码生成器,文中的示例代码讲解详细,感兴趣的小伙伴可以了解一下
    2023-03-03
  • java.lang.NullPointerException异常问题解决方案

    java.lang.NullPointerException异常问题解决方案

    这篇文章主要介绍了java.lang.NullPointerException异常问题解决方案,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-08-08
  • Mybatis CachingExecutor二级缓存使用示例详解

    Mybatis CachingExecutor二级缓存使用示例详解

    这篇文章主要介绍了 Mybatis的CachingExecutor与二级缓存使用示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-09-09
  • idea打开运行配置java web项目的全过程

    idea打开运行配置java web项目的全过程

    这篇文章主要给大家介绍了关于idea打开运行配置java web项目的相关资料,有些时候我们用IDEA跑之前用eclipse中运行的项目的时候,总是不止所措,要不就是只展示html,要不就是不能部署成功,需要的朋友可以参考下
    2023-08-08

最新评论