java并发编程-一章解读volatile

Java代码在编译后会变成Java字节码,字节码被类加载器加载到JVM里,JVM执行字节码,最终需要转化为汇编指令在CPU上执行,Java中所使用的并发机制依赖于JVM的实现和 CPU的指令。

volatile
简要(轻量级的synchronized)
对volatile变量的写操作与普通变量的主要区别有两点:

(1)修改volatile变量时会强制将修改后的值刷新的主内存中。

(2)修改volatile变量后会导致其他线程工作内存中对应的变量值失效。因此,再读取该变量值的时候就需要重新从读取主内存中的值。

在多线程并发编程中synchronized和volatile都扮演着重要的角色,volatile是轻量级的 synchronized,它在多处理器开发中保证了共享变量的“可见性”。
可见性的意思是当一个线程修改一个共享变量时,另外一个线程能读到这个修改的值。如果volatile变量修饰符使用恰当的话,它比synchronized的使用和执行成本更低,因为它不会引起线程上下文的切换和调度。本 文将深入分析在硬件层面上Intel处理器是如何实现volatile的,通过深入分析帮助我们正确地使用volatile变量。

volatile变量规则:对volatile变量的写入操作必须在对该变量的读操作之前执行。

volatile变量规则只是一种标准,要求JVM实现保证volatile变量的偏序语义。结合程序顺序规则、传递性,该偏序语义通常表现为两个作用:
● 保持可见性
● 禁用重排序(读操作禁止重排序之后的操作,写操作禁止重排序之前的操作)
● 程序顺序规则:如果程序中操作A在操作B之前,那么在线程中操作A将在操作B之前执行。
● 传递性:如果操作A在操作B之前执行,并且操作B在操作C之前执行,那么操作A必须在操作C之前执行。

可见性的定义
可见性的定义常见于各种并发场景中,以多线程为例:当一个线程修改了线程共享变量的值,其它线程能够立即得知这个修改。
从性能角度考虑,没有必要在修改后就立即同步修改的值——如果多次修改后才使用,那么只需要最后一次同步即可,在这之前的同步都是性能浪费。因此,实际的可见性定义要弱一些,只需要保证:当一个线程修改了线程共享变量的值,其它线程在使用前,能够得到最新的修改值。

可见性可以认为是最弱的“一致性”(弱一致),只保证用户见到的数据是一致的,但不保证任意时刻,存储的数据都是一致的(强一致)。下文会讨论“缓存可见性”问题,部分文章也会称为“缓存一致性”问题。
可见性导致的伪·重排序
缓存同步顺序本质上是可见性问题。
假设程序顺序(program order)中先更新变量v1、再更新变量v2,不考虑真·重排序:
Core0和Core1是两个核心

  1. Core0先更新缓存中的v1,再更新缓存中的v2(位于两个缓存行,这样淘汰缓存行时不会一起写回内存)。
  2. Core0读取v1(假设使用LRU协议淘汰缓存)。
  3. Core0的缓存满,将最远使用的v2写回内存。
  4. Core1的缓存中本来存有v1,现在将v2加载入缓存。

此时,尽管“更新v1”的事件早于“更新v2”发生,但Core1只看到了v2的最新值,却看不到v1的最新值。这属于可见性导致的伪·重排序:虽然没有实际上没有重排序,但看起来发生了重排序。
可以看到,缓存可见性不仅仅导致可见性问题,还会导致伪·重排序。因此,只要解决了缓存上的可见性问题,也就解决了伪·重排序。

重排序
定义
重排序并没有严格的定义。整体上可以分为两种:
● 真·重排序:编译器、底层硬件(CPU等)出于“优化”的目的,按照某种规则将指令重新排序(尽管有时候看起来像乱序)。
● 伪·重排序:由于缓存同步顺序等问题,看起来指令被重排序了。
重排序也是单核时代非常优秀的优化手段,有足够多的措施保证其在单核下的正确性。在多核时代,如果工作线程之间不共享数据或仅共享不可变数据,重排序也是性能优化的利器。然而,如果工作线程之间共享了可变数据,由于两种重排序的结果都不是固定的,会导致工作线程似乎表现出了随机行为。
问题来源
重排序问题无时无刻不在发生,源自三种场景:

  1. 编译器编译时的优化
  2. 处理器执行时的乱序优化
  3. 缓存同步顺序(导致可见性问题)
    场景1、2属于真·重排序;场景3属于伪·重排序

定义
Java编程语言允许线程访问共享变量,为了 确保共享变量能被准确和一致地更新,线程应该确保通过排他锁单独获得这个变量。

Java语言提供了volatile,在某些情况下比锁要更加方便。

如果一个字段被声明成volatile,Java线程内存模型确保所有线程看到这个变量

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值