前言
小伙伴们大家好,上次分析了Synchronized关键字的特点及使用方式,多线程中经常提到的除了这个还有volatile,来分析该关键字的特点
一、volatile的特点
1.线程间可见性
用volatile声明的共享变量,保证了某个线程修改了该变量的值,新值对其他线程来说是立即可见的,因为volatile关键字强制将修改后的值立即写入内存。
1.1、案例
在main方法里,新建一个线程休眠100ms,然后修改stop变量为true,与此同时通过countNum方法计数,直到stop变量为true停止,结果如下,一直循环表明检测不到stop变为true
public class VolatileTest {
static boolean stop = false;
public static void main(String[] args) {
new Thread(() -> {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
stop = true;
System.out.println("change stop to true...");
}).start();
countNum();
}
static void countNum() {
int i = 0;
while (!stop) {
i++;
}
System.out.println("stopped... successfully at :"+ i);
}
}
1.2 案例分析
解决方法之一就是使用volatile关键字来声明变量,让其他线程可见,在stop修改后第一时间获取,修改后的结果如下,在i变量值为218467224的时候该线程检测到stop的值为true,跳出循环并打印;
static volatile boolean stop = false;
2、禁止指令重排
在编译器和处理器优化指令执行顺序时,为了提高程序性能,可能会对指令进行重排。然而,在多线程环境下,指令重排可能会导致结果的错误或者不符合预期。使用volatile关键字修饰的变量,在读写操作前后会加入特定的内存屏障(memory barrier),这个内存屏障可以防止指令重排,确保操作的顺序符合程序员的预期。
说人话(bushi),具体来说,volatile关键字禁止的是以下三种类型的指令重排:
- 在volatile写操作之前的读操作不能被重排到volatile写操作之后。
- 在volatile写操作之后的写操作不能被重排到volatile写操作之前。
- 在volatile读操作之后的读操作不能被重排到volatile读操作之前。
//伪代码举个例子
int x;
int y;
方法1(){
x=1;
y=1;
}
方法2(result r){
r.r1 = y;
r.r2 = x;
}
解决方案
在变量上添加volatile,禁止指令重排序,则可以解决问题 ,注意只能将volatile添加到y变量上,因为关键字添加的屏障如下
- 写操作加的屏障是阻止上方其它写操作越过屏障排到volatile变量写之下
- 读操作加的屏障是阻止下方其它读操作越过屏障排到volatile变量读之上,因为此时y是正常变量也因为volatile声明了x导致y不可读
但是不用慌,有问题就会有小妙招
章末
好了,以上就是全部内容了,下次来分析分析其他的锁(什么?还有高手)
原文地址:https://blog.csdn.net/TM007_/article/details/134677033
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_26646.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!