Java内存模型
内存模型抽象
Java中每个线程都有自己的工作内存,每个工作内存都有变量的一个副本,线程对变量的操作都在工作内存中,完成后会将工作内存中的变量刷到主内存中。
重排序
编译器优化的重排序。编译器在不改变单线程程序语义的前提下,可以重新安排语句的执行顺序。
指令并行的重排序。编译器在不改变单线程程序语义的前提下,可以重新安排语句的执行顺序。
内存系统的重排序。由于处理器使用缓存和读/写缓冲区,这使得加载和存储操作看上去可能是在乱序执行。
内存屏障指令
为了保证内存可见性,Java 编译器在生成指令序列的适当位置会插入内存屏障指令来禁止特定类型的处理器重排序,主要是以下4种
LoadLoad Barriers
Load1; LoadLoad; Load2;
保证Load1的数据在Load2及之后的load前加载
StoreStore Barriers
Store1; StoreStore; Store2
保证Store1的数据先于Store2及之后的数据 在其他处理器可见
LoadStore Barriers
Load1; LoadStore; Store2
保证Load1的数据的加载在Store2和之后的数据flush前
StoreLoad Barriers
Store1; StoreLoad; Load2
保证Store1的数据在其他处理器前可见(如flush到内存)先于Load2和之后的load的数据的加载。StoreLoad Barrier能够防止load读取到旧数据而不是最近其他处理器写入的数据。
happens-before
程序顺序规则: 如果程序中操作A在操作B之前,那么同一个线程中操作A将在操作B之前进行
监视器锁规则: 在监视器锁上的锁操作必须在同一个监视器锁上的加锁操作之前
执行volatile变量规则: volatile变量的写入操作必须在该变量的读操作之前执行
传递性: 如果操作A在操作B之前执行,并且操作B在操作C之前执行,那么操作A在操作C之前执行。
参考文章