《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成员变量的初始化在对象构造完成之前完成。