大家好,又见面了,我是你们的朋友全栈君。
很长一段时间中对于volatile关键字都是一知半解的,由于工作中用的比较少,也没有对其深入了解,直到看了《深入理解java虚拟机》之后,才有进一步的了解。
volatile是java虚拟机提供的最轻量级的同步机制,只能作用于变来那个,具备两种特性:
- 保证此变量对所有线程的可见性:可见性是指一旦一个线程修改了此变量的值,其他线程能立即得知。
- 禁止指令的重排序(本文暂不涉及)
由于volatile的可见性分析是基于java内存模型的,此处对java内存模型做个简单的概述。
java内存模型
主内存和工作内存
- 主内存:所有的变量都存储在主内存中
- 工作内存:每条线程都有自己的工作内存,线程的工作内存中保存了被该线程使用到的主内存副本拷贝,线程对变量的所有操作都必须在工作内存中进行,不能直接从主内存中读写变量,不同线程之间也无法访问其他线程工作内存中的变量,线程之间变量值的传递只能通过主内存完成。
线程-工作内存-主内存三种之间的关系图
java内存间相互操作(八种内存操作指令)
- 指令功能: 完成主内存和工作内存之间的交互, 主要功能为实现变量从主内存拷贝到工作内存,如何从工作内存同步会主内存
- 指令详解:
- lock(锁定):作用于主内存中的变量,限制该变量为一个线程独占的状态
- unlock(解锁):作用于主内存的变量,将变量从一个线程独占的状态中释放出来,释放后的变量才能被其他变量占用。
- read(读取):作用主内存的变量,将一个变量从主内存加载到工作内存,以便之后的load操作使用。
- load(载入):作用于工作内存,它把read读取的变量值放到工作内存的变量副本中
- use(使用):作用于工作内存,把工作内存中的变量的值传递给执行引擎,每当虚拟机遇到需要使用变量的值的字节码指令是会执行此操作
- assign(赋值):作用于工作内存,把从执行引擎中接收到的值赋值给工作内存的变量,每当虚拟机遇到给变量赋值的字节码指令是执行此操作
- store(存储):作用于工作内存,把工作内存中的变量传送到主内存中,以便之后的write操作使用。
- 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并不具备线程同步到特性!
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/161298.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...