《Java 并发编程实战》02 阅读笔记

115 阅读2分钟

Java 是如何解决可见性和有序性问题的?

为了解决可见性和有序性问题,Java 给程序员提供了按需禁用缓存和编译优化的方法。
这些方法包括 volatilesynchronizedfinal 三个关键字,以及六项 Happens-Before 规则。

在 Java 语言里面,Happens-Before 的语义本质上是一种可见性,A Happens-Before B 意味着 A 事件对 B 事件来说是可见的,无论 A 事件和 B 事件是否发生在同一个线程里。

Happens-Before 规则如下:

  • 前面的操作 Happens-Before 于后续的任意操作,也即程序前面对某个变量的修改一定是对后续操作可见的
  • 对一个 volatile 变量的写操作, Happens-Before 于后续对这个 volatile 变量的读操作
  • 如果 A Happens-Before B,且 B Happens-Before C,那么 A Happens-Before C
  • 对一个锁的解锁 Happens-Before 于后续对这个锁的加锁
  • 如果线程 A 调用线程 B 的 start() 方法(即在线程 A 中启动线程 B),那么该 start() 操作 Happens-Before 于线程 B 中的任意操作
  • 如果在线程 A 中,调用线程 B 的 join() 并成功返回,那么线程 B 中的任意操作 Happens-Before 于该 join() 操作的返回

课后的思考题很有意思:
有一个共享变量 abc,在一个线程里设置了 abc 的值 abc = 3,思考一下,有哪些办法可以让其他线程能够看到 abc == 3 ?

答:

  1. 定义 abc 为 volatile
  2. 使用 synchronized
  3. 设置 abc 为 3 后再调用线程 start 方法
  4. 设置 abc 为 3 后再由主线程调用该线程的 join 方法
  5. 设置 abc 为 3 后定义一个 volatile 变量,在其他线程中,先读取后面定义的 volatile 变量再读取 abc