Junhc

岂止于博客

Java内存模型(JMM)

Java内存模型(JMM)
原子性(Atomicity)

原子性是指一个操作是不可中断的。即使是在多个线程一起执行的时候,一个操作一旦开始,就不会被其他线程干扰。

可见性(Visibility)

可见性是指一个线程修改了某一个共享变量的值,其他线程是否能够立即知道这个修改。 显然,对于串行程序来说,可见性问题是不存在的。因为你再任何一个操作步骤中修改了某个变量,那么在后续的步骤中,读取这个变量的值,一定是修改后的新值。 但是并行程序就不见得了,如果在 CPU1 和 CPU2 上各运行了一个线程,它们共享变量 t,由于编译器优化或者硬件优化的缘故,在 CPU1 上的线程将变量 t 进行了优化, 将其缓存在 cache 中或者寄存器里。这种情况下,如果 CPU2 上的某个线程修改了变量 t 的实际值,那么 CPU1 上的线程可能并无法意识到这个改动,依然会读取 cache 中 或者寄存器的数据。因此,就产生了可见性的问题。

有序性(Ordering)

对于一个线程的执行代码而言,我们总是习惯地认为代码的执行是从先往后,依次执行的。这么理解也不能说完全错误,因为就一个线程内而言,确实会表现成这样。 但是,在并发时,程序的执行可能就会出现乱序。给人直观的感觉就是:写在前面的代码,会在后面执行。 有序性问题的原因是因为程序在执行时,可能会进行指令重排,重排后的指令与原指令的顺序未必一致。

哪些指令不能重排:Happen-Before 规则
  • 程序顺序原则:一个线程内保证语义的串行性
  • volatile 规则:volatile 变量的写,先发生于读,这保证了 volatile 变量的可见性
  • 锁规则:解锁(unlock)必须发生在随后的加锁(lock)前
  • 传递性:A先于B,B先于C,那么A必然先于C
  • 线程的 start() 方法先于它的每一个动作
  • 线程的所有操作先于线程的终结(Thread.join())
  • 线程的中断(interrupt())先于被中断线程的代码
  • 对象的构造函数执行、结束先于 finalize() 方法
参考资料

Java内存模型