【线程】Volatile关键字

Volatile是Java虚拟机提供的轻量级同步机制

什么是可见性

这里可以举个例子
在这里插入图片描述
图中线程A读取了主内存中的flag变量,在线程A运行的时候,线程B将主内存中的变量读取到自己的工作内存中,将true改为false,再刷新回主内存中
在这里插入图片描述
如果不能保证可见性,程序A会认为flag一直是true,就算实际的flag已经变成了false
而在对应的flag变量上添加volatile关键字,就可以保证可见性,也就是说只要主内存中的flag值被修改了,线程A就会第一时间知道

不保证原子性

比如执行多个线程来对一个变量进行++操作,因为++操作本身不满足原子性,所以将这个变量修改为volatile关键字也不会得到最终正确的结果
这时候我们就可以使用原子类进行操作,其原理是CAS

什么是指令重排

我们平时写的程序,计算机并不一定是按照我们写的这样去执行的
比如

int x=0;	//1
int y=1;	//2
x=x+1;		//3
y=x+x;		//4

我们预想的情况是计算机是按照1234顺序执行的
但是计算机实际上是按照2134,1324等顺序执行的,但是最终结果没有错误
但是放在多线程情况下,就可能导致错误

线程A线程B
a=4b=3
x=by=a

假设a和b的初始值都是0,则按照我们的想法,两个线程是并行执行的,应该同时进行第一条语句与第二条语句,最后得出的结果应该是x=3,y=4
但是指令重排可能会导致下面两条语句先执行,上面两条语句再执行,这样在本线程内是没有错误的,但是在整个代码逻辑上就会得出x=0,y=0的情况
还可以举一个例子

 public volatile boolean testMark=false; // 共享变量
 Map configOptions;
 char[] configText;

//线程1 逻辑
{
   //模拟读取配置信息, 当读取完成后把 testMark 设置为ture 作为通知 其他线程 配置可以读取了
   configOptions=new HashMap<>();
   //读取配置文件信息
   configText=readConfigFile(fileName);
   //把配置文件信息放入configOptions 
   processConfigOptions(configText,configOptions);
   //标志位设为ture
   testMark=true;
}


//线程2逻辑
{
   //循环判断testMark 等待testMark为true
   while(!testMark ){
   		
   }
   //读取配置信息
   doSomethingWithConfig();
}

如果不禁止 指令重排 线程1 中 把 testMark=true; 重排到了 加载配置信息前面
这个时候线程2 会立即发现 testMark=true; 并进行 配置信息的读取 但是 线程1 仅仅是先执行了testMark=true; 配置文件加载 还没执行,configOptions没有数据 这个时候你如果进行这个中操作 configOptions.get(“token”);就会报错。
参考文章
【狂神说Java】JUC并发编程最新版通俗易懂
volatile 指令重排以及为什么禁止指令重排

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值