java进阶(6)之从硬件底层剖析synchronized/volatile原理

已知:

  • java中的synchronized关键字能保证可见性,有序性,原子性;
  • volatile关键字能保证可见性,有序性。

问题:

  • 为什么java中的并发,在硬件层面不能保证,非要在JVM里处理呢?
  • 它们在硬件层面是如何对应保证的呢?
  • java层面为啥要加这两个关键字才能保证java的并发特性呢?

指令重排序无法保证有序性

java中的一行行代码,对应到硬件层面,就是一个个指令,现代处理器为了加快编译速度,有可能会乱序执行指令,这样也就无法保证代码的有序性了。
在这里插入图片描述

现代CPU缓存模型无法保证可见性和原子性

图解CPU缓存模型

简化版CPU缓存模型请移步:java进阶(4)之volatile关键字深入详解
在这里插入图片描述
1. 高速缓存中的tag表示数据所对应的内存地址,cacheline表示数据本身,flag表示数据状态(E表示exclusive写,S表示shared读)

2. Java层面的读写数据,对应到硬件层面,就是主内存/高速缓存的读写;

3. 处理器与处理器之间的数据交互,或者说处理器与主内存的数据交互,是通过总线的嗅探机制来实现的,也可以说是缓存一致性协议(我把嗅探机制类比成java层面的EventBus);

4. 现代CPU为了加快读写速度,加入了写缓冲器和无效队列,但是这样的话,数据只有读写完成了,才能进入到高速缓存/主内存,这样会导致数据无法及时更新,从而无法保证原子性,可见性。

内存屏障保障有序性和可见性

有序性保障

  • 每个volatile/synchronized写操作前面,加StoreStore屏障,禁止上面的普通写和volatile/synchronized重排;
  • 每个volatile/synchronized写操作后面,加StoreLoad屏障,禁止跟下面的volatile/synchronized读/写重排;
  • 每个volatile/synchronized读操作前面,加LoadLoad屏障,禁止上面的普通读和volatile/synchronized读重排;
  • 每个volatile/synchronized读操作后面,加LoadStore屏障,禁止下面的普通写和volatile/synchronized读重排。

可见性保障

  • volatile/synchronized关键字修饰的变量或者代码块在加载之前,会去硬件底层执行refresh指令,将高速缓存/主内存的最新数据刷新到本地工作内存。
  • volatile/synchronized关键字修饰的变量或者代码块在加载之后,会去硬件底层执行flush执行,将数据刷到高速缓存/主内存中。

synchronized中CAS机制保障原子性

在这里插入图片描述
synchronized关键字修饰的代码块或者方法,会被指令monitorentermonitorexit包裹,包裹的模块可以称之为ObjectMonitor,当有线程进入时,会执行CAS加锁,从而保证了原子性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值