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 Swing实现餐厅点餐系统源码(收藏版)

    Java Swing实现餐厅点餐系统源码(收藏版)

    这篇文章主要介绍了Java Swing实现餐厅点餐系统源码,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-02-02
  • java实现Api接口加密通信方式

    java实现Api接口加密通信方式

    这篇文章主要介绍了java实现Api接口加密通信方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-06-06
  • Spring实现文件上传的配置详解

    Spring实现文件上传的配置详解

    这篇文章将为大家详细说明一下spring上传文件如何配置,以及从request请求中解析到文件流的原理,文中示例代码讲解详细,感兴趣的可以了解一下
    2022-08-08
  • Java调用opencv IDEA环境配置的教程详解

    Java调用opencv IDEA环境配置的教程详解

    这篇文章主要为大家详细介绍了Java调用opencv IDEA环境配置的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2024-03-03
  • SpringCloud配置客户端ConfigClient接入服务端

    SpringCloud配置客户端ConfigClient接入服务端

    这篇文章主要为大家介绍了SpringCloud配置客户端ConfigClient接入服务端,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-08-08
  • Java利用JSONPath操作JSON数据的技术指南

    Java利用JSONPath操作JSON数据的技术指南

    JSONPath 是一种强大的工具,用于查询和操作 JSON 数据,类似于 SQL 的语法,它为处理复杂的 JSON 数据结构提供了简单且高效的解决方案,本文将介绍 JSONPath 的基本语法,并通过详细的 Java 示例展示其实际应用,需要的朋友可以参考下
    2025-04-04
  • 代理模式:JAVA静态代理和动态代理的实例和实现详解

    代理模式:JAVA静态代理和动态代理的实例和实现详解

    这篇文章主要给大家介绍了关于Java静态代理和动态代理的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-08-08
  • Java移除无效括号的方法实现

    Java移除无效括号的方法实现

    本文主要介绍了Java移除无效括号的方法实现,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-08-08
  • SpringCloud Alibaba使用Seata处理分布式事务的技巧

    SpringCloud Alibaba使用Seata处理分布式事务的技巧

    在传统的单体项目中,我们使用@Transactional注解就能实现基本的ACID事务了,随着微服务架构的引入,需要对数据库进行分库分表,每个服务拥有自己的数据库,这样传统的事务就不起作用了,那么我们如何保证多个服务中数据的一致性呢?跟随小编一起通过本文了解下吧
    2021-06-06
  • Java 基于AQS实现一个同步器

    Java 基于AQS实现一个同步器

    这篇文章主要介绍了如何基于AQS实现一个同步器,帮助大家更好的理解和学习Java并发,感兴趣的朋友可以了解下
    2020-09-09

最新评论