JUC并发编程 原理之 volatile -- 保证可见性 & 保证有序性 & 习题 balking模式
Posted Z && Y
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JUC并发编程 原理之 volatile -- 保证可见性 & 保证有序性 & 习题 balking模式相关的知识,希望对你有一定的参考价值。
1. 保证可见性
- 写屏障(sfence)保证在该屏障之前的,对共享变量的改动,都同步到主存当中
public void actor2(I_Result r) {
num = 2;
ready = true; // ready 是 volatile 赋值带写屏障
// 写屏障
}
- 读屏障(lfence)保证在该屏障之后,对共享变量的读取,加载的是主存中最新数据
public void actor1(I_Result r) {
// 读屏障
// ready 是 volatile 读取值带读屏障
if(ready) {
r.r1 = num + num;
} else {
r.r1 = 1;
}
}
2. 如何保证有序性
- 写屏障会确保指令重排序时,不会将写屏障之前的代码排在写屏障之后
public void actor2(I_Result r) {
num = 2;
ready = true; // ready 是 volatile 赋值带写屏障
// 写屏障
}
- 读屏障会确保指令重排序时,不会将读屏障之后的代码排在读屏障之前
public void actor1(I_Result r) {
// 读屏障
// ready 是 volatile 读取值带读屏障
if(ready) {
r.r1 = num + num;
} else {
r.r1 = 1;
}
}
3. 小结
volatile 不能解决指令交错:
- 写屏障仅仅是保证之后的读能够读到最新的结果,但不能保证读跑到它前面去
- 而有序性的保证也只是保证了本线程内相关代码不被重排序
4. balking模式
希望 doInit() 方法仅被调用一次,下面的实现是否有问题,为什么?
分析:
- initialized 被 volatile 修饰 只可以保证变量的可见性,并不能保证多行代码执行的原子性。
- volatile 适用于一个线程写 另外一些线程在读的情况。还可以用于代码在必要的时间禁用指令重排序。
改正方法:
public class TestVolatile {
Boolean initialized = false;
void init() {
synchronized (initialized) {
if (initialized) {
return;
}
doInit();
initialized = true;
}
}
private void doInit() {
}
}
以上是关于JUC并发编程 原理之 volatile -- 保证可见性 & 保证有序性 & 习题 balking模式的主要内容,如果未能解决你的问题,请参考以下文章
JUC并发编程 共享模式之工具 JUC ReentrantLock -- ReentrantLock原理
JUC并发编程 共享模型之内存 -- Java 内存模型 & 原子性 & 可见性(可见性问题及解决 & 可见性 VS 原子性 & volatile(易变关键字))(代码