《Java并发编程的艺术》读书笔记二

《Java并发编程的艺术》读书笔记

Java线程之间的通信是通过共享内存实现,每个线程也又自己的本地内存,这样多线程程序中就会出现可见性问题。

在执行程序时,为了提供性能,编译器和处理器会对指令做重排序。

为了多线程程序能正确执行,需要解决上面的两个问题。

通过在指令中加入内存屏障和happends-before规则来解决以上问题。

内存屏障有四种:

  • LoadLoad Barriers

    确保该指令之前的数据的装载先于之后的数据装载

  • StoreStore Barriers

    确保该指令之前的数据对其他处理器的可见性(刷新到主存)先于之后的数据

  • LoadStore Barriers

    确保该指令之前的数据加载先于之后数据的刷新

  • StoreLoad Barriers

    确保该指令之前的数据刷新先于之后的数据加载

happens-before规则前后的操作不会进行重排序,规则有下面几条:

  • 程序次序规则

    线程中的每个动作A都happens-before于该线程中的每一个动作B,其中,在程序中,所有动作B都能出现在A后面。

  • 监视器锁规则

    对于一个监视器锁的解锁happens-before于每一个后续对同一监视器锁的加锁。

  • volatile变量规则

    对volatile域的写入操作happens-before于每一个后续对同一个域的读写操作。

  • 线程启动规则

    在一个线程里,对Thread.start的调用会happens-before于每个启动线程的动作。

  • 线程终结规则

    线程中的任何动作都happens-before于其他线程检测到这个线程已经终结、或者从Thread.join调用中成功返回,或Thread.isAlive返回false。

  • 中断规则

    一个线程调用另一个线程的interrupt happens-before于被中断的线程发现中断。

  • 终结规则

    一个对象的构造函数的结束happens-before于这个对象finalizer的开始。

  • 传递性

    如果A happens-before于B,且B happens-before于C,则A happens-before于C。

volatile和final的内存语义得到了增强,volatile的变量在某些情况下不会重排序,volatile的64位变量的读写是原子的。final成员变量的初始化在对象构造完成之前完成。

重排序