简介
java内存模型(Java Memory Model,JMM)定义了多线程下内存访问的规则,屏蔽了底层硬件的差异,目的是解决多线程环境下共享数据的原子性、可见性、和有序性。理解 JMM 是编写正确、高效并发程序的基础,synchronized、volatile、final 等关键字均基于 JMM 实现其语义。
核心概念
- 主内存(Main Memory)
共享变量存在主内存中,线程共享。 - 工作内存(Working Memory)
每个线程有自己的工作内存,存错操作主内存变量的副本。线程对变量的操作在自己的工作内存中修改,不能直接操作主内存 - 内存屏障(Memory Barrier)
一组规则,用于控制指令重排序和内存可见性,例如 volatile、synchronized 等关键字会插入内存屏障。
三大特性
-
可见性(Visibility)
多线程对共享变量的修改必须对其他线程可见 -
原子性(Atomicity)
对共享变量的修改要么全部执行成功,要么不执行 -
有序性(Ordering)
程序执行的顺序需符合预期,避免因指令重排序导致结果异常
Happens-Before 规则
-
程序次序法则:
线程中的每个动作A都happens-before于该线程中的每一个动作B,其中,在程序中,所有的动作B都出现在动作A之后。 -
监视器锁法则:
对一个监视器锁的解锁happens-before 于每一个后续对同一监视器锁的加锁。 -
volatile 变量法则:
对 volatile 域的写入操作 happens-before 于每一个后续对同一域的读操作. -
线程启动法则:
在一个线程里,对Thread.start的调用会happens-before 于每一个启动线程中的动作。即在主线程调用子线程的start()方法前的所有操作对子线程可见。 -
线程终结法则:
线程中的任何动作都happens-before 于其他线程检测到这个线程已经终结、或者从 Thread.join 调用中成功返回,或者 Thread.isAlive 返回 false.即在主线程中调用子线程的join()方法,子线程中所有的操作对主线程可见。 -
中断法则:
一个线程调用另一个线程的interrupt happens-before 于被中断的线程发现中断(通过抛出InterruptedException,或者调用 isInterrupted 和interrupted ). -
终结法则:
一个对象的构造函数的结束happens-before于这个对象finalizer的开始。 -
传递性:
如果Ahappens-before于B,且B happens-before于C,则A happens-before于C.