关于并发关键字`Volatile`


title: java-volatile
date: 2022-04-21 14:13:25
tags:

  • 学习
  • 转载与汇总
  • java并发

来自我的博客 :ZWN的Blog,https://zwn2001.github.io/2022/04/21/java-volatile/

关于并发关键字Volatile

volatile通常被比喻成"轻量级的synchronized",也是Java并发编程中比较重要的一个关键字。和synchronized不同,volatile是一个变量修饰符,只能用来修饰变量。无法修饰方法及代码块等。

Javavolatile关键字用于标记一个变量 “应当存储在主存” 。更确切地说,每次读取volatile变量,都应该从主存读取,而不是从CPU缓存读取。每次写入一个volatile变量,应该写到主存中,而不是仅仅写到CPU缓存。

实际上,从Java 5开始,volatile关键字除了保证volatile变量从主存读写外,还提供了更多的保障。

变量可见性问题

Javavolatile关键字能保证变量修改后,对各个线程是可见的。这个听起来有些抽象,下面就详细说明。

在一个多线程的应用中,线程在操作非volatile变量时,出于性能考虑,每个线程可能会将变量从主存拷贝到CPU缓存中。如果你的计算机有多个CPU,每个线程可能会在不同的CPU中运行。这意味着,每个线程都有可能会把变量拷贝到各自CPU的缓存中,如下图所示:

对于非volatile变量,JVM并不保证会从主存中读取数据到CPU缓存,或者将CPU缓存中的数据写到主存中。这会引起一些问题。试想一下,如果有两个以上的线程访问一个共享对象,这个共享对象包含一个counter变量,下面是代码示例:

public class SharedObject {
   
    public int counter = 0;
}

如果只有线程1修改了(自增)counter变量,而线程1和线程2两个线程都会在某些时刻读取counter变量。

如果counter变量没有声明成volatile,则counter的值不保证会从CPU缓存写回到主存中。也就是说,CPU缓存和主存中的counter变量值并不一致,如下图所示:

这就是“可见性”问题,线程看不到变量最新的值,因为其他线程还没有将变量值从CPU缓存写回到主存。一个线程中的修改对另外的线程是不可见的。这其实是非常常见的一类问题。

volatile可见性保证

可见性是指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。

Javavolatile关键字就是设计用来解决变量可见性问题。将counter变量声明为volatile,则在写入counter变量时,也会同时将变量值写入到主存中。同样的,在读取counter变量值时,也会直接从主存中读取。

下面的代码演示了如果将counter声明为volatile

public class SharedObject {
   
    public volatile int counter = 0;
}

将一个变量声明为volatile,可以保证变量写入时对其他线程的可见。

在上面的场景中,一个线程(T1)修改了counter,另一个线程(T2)读取了counter(但没有修改它),将counter变量声明为volatile,就能保证写入counter变量后,对T2是可见的。

然而,如果T1和T2都修改了counter的值,只是将counter声明为volatile还远远不够,后面会有更多的说明。

完整的volatile可见性保证

实际上,volatile的可见性保证并不是只对于volatile变量本身那么简单。可见性保证遵循以下规则:

  • 如果线程A写入一个volatile变量,线程B随后读取了同样的volatile变量,则线程A在写入volatile变量之前的所有可见的变量值,在线程B读取volatile变量后也同样是可见的。
  • 如果线程A读取一个volatile变量,那么线程A中所有可见的变量也会同样从主存重新读取。

下面用一段代码来示例说明:

public 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值