JMM内存模型-同步动作与安全发布

1 JMM内存模型

由于存在编译器优化、Processor流水线优化、缓存优化等,我们编写的代码不一定是实际运行的代码,我们编写的代码顺序不一定是实际执行的顺序,会出现可见性、原子性、有序性问题。所以我们需要学习JMM内存模型来解决上面的问题。

1.1 什么是JMM

内存模型就是多线程下对共享变量的一组读写规则

  • 共享变量值是否在线程间同步
  • 代码可能的执行顺序
  • 需要关注的操作就有两种 Load、Store
  • Load 就是从缓存读取到寄存器中,如果一级缓存中没有,就会层层读取二级、三级缓存,最后才是Memory
  • Store 就是从寄存器运算结果写入缓存,不会直接写入 Memory,当 Cache line 将被 eject 时,会
    writeback 到 Memory

1.2 JMM规范

1.2.1 规则1 - Race Condition

多线程下,没有依赖关系的代码,在执行共享变量读写操作(至少有一个线程写)时,并不能保证以编写顺序(Program Order)执行,这称为发生了竞态条件(Race Condition)。
例如:
有共享变量x、y,线程1执行

r.r1 = y;
r.r2 = x;

线程2执行

x = 1;
y = 1;

最终的结果可能是 r1==1 而 r2==0

y = 1;
r.r1 = y;
r.r2 = x;
x = 1;
1.2.2 规则2 - Synchronization Order

若要保证多线程下,每个线程的执行顺序(Synchronization Order)按编写顺序(Program Order)执行,那么必须使用 Synchronization Actions(同步动作) 来保证,这些 SA 有

  • lock,unlock - synchronized, ReentrantLock
  • volatile 方式读写变量 - 保证可见性,防止重排序
  • VarHandle 方式读写变量
    例如:
    用 volatile 修饰共享变量 y,线程 1 执行
r.r1 = y;
r.r2 = x;

线程 2 执行

x = 1;
y = 1;

最终的结果就不可能是 r1==1 而 r2==0

1.2.3 规则3 - Happens-Before

线程切换时代码的顺序和可见性
若是变量读写时发生线程切换(例如,线程 1 写入 x,切换至线程 2,线程 2 读取 x)在这些边界的处理上如果有action1 先于 action 2 发生,那么代码可以按确定的顺序执行,这称之为 Happens-Before Order 规则。
用公式表达为
在这里插入图片描述

含义为:如果 action1 先于 action2 发生,那么 action1 之前的共享变量的修改对于 action2 可见,且代码按顺序执行。
具体规则
其中 代表线程,而 x 未加说明,是普通共享变量,使用 volatile 会单独说明
1)线程的启动和运行边界
在这里插入图片描述
2)线程的结束和 join 边界
在这里插入图片描述
3)线程的打断和得知打断边界
在这里插入图片描述
4)unlock 与 lock 边界
在这里插入图片描述
5)volatile write 与 volatile read 边界
在这里插入图片描述
6)传递性
在这里插入图片描述

1.2.4 规则4 - Causality

Causality 即因果律:代码之间如存在依赖关系,即使没有加 SA 操作,代码的执行顺序也是可以预见的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值