多线程之volatile

多线程之volatile

线程同步另一个重要方面是内存可见性, 加锁不仅保证互斥同样保证可见。

JMM

Java内存模型简称JMM(Java Memory Model

Screen Shot 2020-08-21 at 4.43.35 PM

  • 主内存: 主内存被所有的线程所共享,对于一个共享变量(比如静态变量,或是堆内存中的实例)来说,主内存当中存储了它的“本尊”。
  • 工作内存: 简单理解为计算机当中的CPU高速缓存,但又不完全等同。每一个线程拥有自己的工作内存,对于一个共享变量来说,工作内存当中存储了它的“副本”。

指令重排

指令重排是指JVM在编译Java代码的时候,或者CPU在执行JVM字节码的时候,对现有的指令顺序进行重新排序。指令重排的目的是为了在不改变程序执行结果的前提下,优化程序的运行效率。但是在某些情况下,会影响到多线程的执行结果

eg:

  • 有可能readerThread 看不到ready为true, 一直循环
  • 也有可能看不到number = 42, 输出0
Screen Shot 2020-08-21 at 4.52.08 PM

Volatile

volatile 是比synchronized 关键字更轻量级的同步机制。

保证可见

对一个volatile变量的读,(任意线程)总是能看到对这个volatile变量最后的写入。

  1. 一个线程修改volatile变量的值时,该变量的新值会立即刷新到主内存中,这个新值对其他线程来说是立即可见的。
  2. 一个线程读取volatile变量的值时,该变量在本地内存中缓存无效,需要到主内存中读取。

保证有序

禁止重排序规则

boolean inited = false;// 初始化完成标志
//线程1:初始化完成,设置inited=true
new Thread() {
public void run() {
context = loadContext(); //语句1
inited = true; //语句2
};
}.start();
//线程2:每隔1s检查是否完成初始化,初始化完成之后执行doSomething方法
new Thread() {
public void run() {
while(!inited){
Thread.sleep(1000);
}
doSomething(context);
};
}.start();

期望行为: 线程1初始化配置,初始化完成,设置inited=true。线程2每隔1s检查是否完成初始化,初始化完成之后执行doSomething方法。

潜在问题: 线程1中,语句1和语句2之间不存在数据依赖关系,JMM允许这种重排序。例如在**程序执行过程中发生重排序,先执行语句2后执行语句1: 线程1 先执行语句2, 配置并未加载,而线程2 读取到inited=true,开始执行后续操作。。。

volatile修饰inited,这样不会重排

典型用法: 检查某个标记以判断是否退出循环。

volatile boolen asleep; 
...
while (!asleep) {
countSomeSheep();
}
### 不保证原子性

public class VolatileTest {
public volatile int a = 0;

public void increase() {
a++;
}

public static void main(String[] args) {
final VolatileTest test = new VolatileTest();
for (int i = 0; i < 10; i++) {
new Thread() {
public void run() {
for (int j = 0; j < 1000; j++)
test.increase();
};
}.start();
}

while (Thread.activeCount() > 1) {
// 保证前面的线程都执行完
Thread.yield();
}
System.out.println(test.a);
}
}

a++ 并不是原子操作 (读取-修改-写入)

解决:

  • synchronized
  • CAS - AtomicInteger

(Optional). Volatile 原理

java编译器在生成字节码时,在volatile变量操作前后的指令序列中插入内存屏障来禁止特定类型的重排序。

总结

并发编程中,常用volatile修饰变量以保证变量的修改对其他线程可见。

volatile可以保证可见性和有序性,不能保证原子性。

volatile是通过插入内存屏障禁止重排序来保证可见性和有序性的。


参考

https://zhuanlan.zhihu.com/p/56191979

https://mp.weixin.qq.com/s?__biz=MzAxMjEwMzQ5MA==&mid=2448888521&idx=1&sn=c880331ef37b5f111f553ad0b4064bab&scene=21#wechat_redirect