java volatile可见性解析

java volatile可见性解析很长一段时间中对于volatile关键字都是一知半解的,由于工作中用的比较少,也没有对其深入了解,直到看了《深入理解java虚拟机》之后,才有进一步的了解。   volatile是java虚拟机提供的最轻量级的同步机制,只能作用于变来那个,具备两种特性:保证此变量对所有线程的可见性:可见性是指一旦一个线程修改了此变量的值,其他线程能立即得知。禁止指令的重排序(本文暂不涉及)由于vol

大家好,又见面了,我是你们的朋友全栈君。

      很长一段时间中对于volatile关键字都是一知半解的,由于工作中用的比较少,也没有对其深入了解,直到看了《深入理解java虚拟机》之后,才有进一步的了解。
      volatile是java虚拟机提供的最轻量级的同步机制,只能作用于变来那个,具备两种特性:

  • 保证此变量对所有线程的可见性:可见性是指一旦一个线程修改了此变量的值,其他线程能立即得知。
  • 禁止指令的重排序(本文暂不涉及)

由于volatile的可见性分析是基于java内存模型的,此处对java内存模型做个简单的概述。

java内存模型

主内存和工作内存

  • 主内存:所有的变量都存储在主内存中
  • 工作内存:每条线程都有自己的工作内存,线程的工作内存中保存了被该线程使用到的主内存副本拷贝,线程对变量的所有操作都必须在工作内存中进行,不能直接从主内存中读写变量,不同线程之间也无法访问其他线程工作内存中的变量,线程之间变量值的传递只能通过主内存完成。


线程-主内存-工作内存三者之间的关系






线程-工作内存-主内存三种之间的关系图

java内存间相互操作(八种内存操作指令)

  • 指令功能: 完成主内存和工作内存之间的交互, 主要功能为实现变量从主内存拷贝到工作内存,如何从工作内存同步会主内存
  • 指令详解:
    1. lock(锁定):作用于主内存中的变量,限制该变量为一个线程独占的状态
    2. unlock(解锁):作用于主内存的变量,将变量从一个线程独占的状态中释放出来,释放后的变量才能被其他变量占用。
    3. read(读取):作用主内存的变量,将一个变量从主内存加载到工作内存,以便之后的load操作使用。
    4. load(载入):作用于工作内存,它把read读取的变量值放到工作内存的变量副本中
    5. use(使用):作用于工作内存,把工作内存中的变量的值传递给执行引擎,每当虚拟机遇到需要使用变量的值的字节码指令是会执行此操作
    6. assign(赋值):作用于工作内存,把从执行引擎中接收到的值赋值给工作内存的变量,每当虚拟机遇到给变量赋值的字节码指令是执行此操作
    7. store(存储):作用于工作内存,把工作内存中的变量传送到主内存中,以便之后的write操作使用。
    8. write(写入):作用于主内存,将store操作中传递过来的值存储到主内存变量中。

如何实现volatile的可见性

声明: T为一个线程 V为volatile变量
1. 保证自己所在的线程可见其他线程对变量所作的修改
– 线程T对变量V执行的前一个动作是load的时候,线程T才能对变量V执行use操作,线程T对变量执行的后一个操作是use的时候,线程T才能对变量执行load操作。换句话说,线程T对变量V执行的操作中,read(read和load绑定一起工作), load和use必须绑定在一起。保证了自己所在的线程获取到的变量数据永远是最新的。
2. 保证自己所在线程对变量的修改对其他线程是可见的。
– 线程T对变量V执行的前一个动作是assign的时候,线程T才能对变量V执行store操作,线程T对变量V执行的后一个操作是use的时候,线程T才能对变量V执行assign操作,换句话说,线程T对变来那个V执行的操作中,assign, store,write(store和write一起工作)必须绑定在一起工作,保证了自己所在线程的修改对其他线程来说是可见的。

可见性推论:由上述两条规则可知,当执行引擎想要使用某一个volatile变量的时候,他必须从再次从主内存中读取变量刷新工作内存中的变量值。当执行引擎对某个变量执行完某操作并希望将该变量存入工作内存中时,必须同步将该变量的值同步到主内存中。

volatile不具备线程安全性

  • 从以上的分析中可以得出volatile实现了线程之间的可见性,但是volatile并不具备线程安全的特性。
    原因:以上的可见性分析只是针对单个线程而言的,但是当两个线程分别对同一个变量V执行read操作,并对读取后的变量执行相关的运算,之后两个线程会将自己操作的变量同步会主内存,这时候就会存在后同步到操作会覆盖前一个同步到操作。

总结:volatile关键字保证了不同线程对变量的修改对于其他线程来说是立即可见的,但volatile并不具备线程同步到特性!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/161298.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Python开发工具PyCharm介绍

    Python开发工具PyCharm介绍PyCharm 是一种 PythonIDE 带有一整套可以帮助用户在使用 Python 语言开发时提高其效率的工具 比如调试 语法高亮 Project 管理 代码跳转 智能提示 自动完成 单元测试 版本控制 此外 该 IDE 提供了一些高级功能 以用于支持 Django 框架下的专业 Web 开发 特点首先 PyCharm 拥有一般 IDE 具备的功能 比如 调试 语法高亮 Project 管理 代码跳转 智能提示 自动完成 单元测试 版本控制另外 PyCharm 还提供了一些很好的功

    2025年12月8日
    4
  • mysql分区之range分区「建议收藏」

    mysql分区之range分区「建议收藏」随着互联网的发展,各方面的数据越来越多,从最近两年大数据越来越强的呼声中就可见一斑。我们所做的项目虽算不上什么大项目,但是由于业务量的问题,数据也是相当的多。数据一多,就很容易出现性能问题,而为了解决这个问题我们通常很容易想到集群、分片等。但是在某些时候却不一定必须要用集群、分片,也可以适当的使用数据分区。什么是分区?(以下引用自:http://wangweiak47.blog.51

    2022年5月7日
    42
  • __setattr__,setattr(),getattr__,getattr()及__getattribute__的区别

    __setattr__,setattr(),getattr__,getattr()及__getattribute__的区别Python2.7IDEPycharm5.0.3首先,给一波定义__setattr__(self,name,value)#当试图给特性name赋值时候自动被调用,其余方法同理#相当于触发机制__getattribute__(self,item)#每次通过实例化访问属性都会通过该函数#如果没有该属性,则访问完该函数后,再会通过__getattr__函数_setattr_和_get

    2025年6月23日
    3
  • Lc5-最长回文字串

    Lc5-最长回文字串Lc5-最长回文子串js求数组求字符串的长度都是length方法js字符串截取,varlongestPalindrome=function(s){letres=”;for(leti=0;i<s.length;i++){letl=i-1,r=i+1;sub(l,r);l=i,r=i+1;sub(l,r);fu

    2022年7月24日
    9
  • unittest测试框架简介

    unittest测试框架简介unitest测试框架简介

    2022年10月14日
    5
  • markdown导出为html_python html转word

    markdown导出为html_python html转word关于前端HTML转换为Markdown,发现了一个非常好用的npm项目:https://sitdown.mdnice.com/zh-hans/首先确保本机已经安装nodejs,并根据下面的文章安装execjs并修改其源码:execjs执行包含中文参数的JavaScripthttps://xxmdmst.blog.csdn.net/article/details/123099139在python所在目录安装sitdown:>npminstallsitdownadded2pac

    2025年10月2日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号