Java内存模型:如何解决有序性和可见性问题

继上一篇:多线程安全问题:可见性、原子性、有序性

引言


  1. Happens-Before 的语义本质上是一种可见性
    A Happens-Before B 意味着 A 事件对 B 事件来说是可见的,无论 A 事件和 B 事件是否发生在同一个线程里。
  2. 三个关键字:synchronized、volatile、final

什么是Java内存模型

Java内存模型规范了JVM如何按需禁用内存和编译优化
具体包括:三个关键字(synchronized、volatile、final)及Happens-Before原则

Volatile关键字

  1. 原始语义,如 volatile int x = 0,表达的是:告诉编译器,对这个变量的读写,不能使用 CPU 缓存,必须从内存中读取或者写入。

final关键字

  1. final 修饰变量时,初衷是告诉编译器:这个变量生而不变,可以可劲儿优化。
  2. 避免构造函数 ”逸出“
final int x;
public FinalFieldExample() {
      x = 3;
      y = 4;
      global.obj = this; // this逸出;线程通过 global.obj 读取 x 有可能读到 0 
}

Happens-Before原则

  1. 前面一个操作的结果对后续操作是可见的
  2. 具体规则:
  • 程序的顺序性规则:程序前面对某个变量的修改一定是对后续操作可见的
  • Volatile变量规则:对一个 volatile 变量的写操作, Happens-Before 于后续对这个 volatile 变量的读操作
  • 传递性规则:如果 A Happens-Before B,且 B Happens-Before C,那么 A Happens-Before C
  • 管程锁规则:对一个锁的解锁 Happens-Before 于后续对这个锁的加锁。
  • 线程start()规则:如果线程 A 调用线程 B 的 start() 方法,那么该start() 操作 Happens-Before 于线程 B 中的任意操作。
  • 线程join()规则:如果在线程 A 中,调用线程 B 的 join() 并成功返回,那么线程 B 中的任意操作 Happens-Before 于该 join() 操作的返回
  • 线程interrupt()规则:对线程interrupt() 方法的调用先行发生于被中断线程的代码检测到中断事件的发生
  • 对象finalize规则:一个对象的初始化完成先行发生于他的finalize() 方法的开始

重点:Volatile变量规则

你可能感兴趣的:(Java内存模型:如何解决有序性和可见性问题)