Java并发:内存模型

2019/07/09

内存模型

什么是内存模型

可见性的原因是缓存,导致有序性的原因是编译优化,那解决可见性、有序性最直接的办法就是禁用缓存和编译优化,但是这样问题虽然解决了,我们程序的性能可就堪忧了。

合理的方案应该是按需禁用缓存以及编译优化

Java 内存模型规范了 JVM 如何提供按需禁用缓存和编译优化的方法。具体来说,这些方法包括 volatilesynchronizedfinal 三个关键字,以及七项 Happens-Before 规则和它的特性

volatile

早在C语言里就有volatile了,最原始的意义就是禁用CPU缓存。也就是必须从内存中读取或者写入

下面的代码中,如果Java在低于 1.5 版本上运行,x 可能是 42,也有可能是 0;如果在 1.5 以上的版本上运行,x 就是等于 42。

class VolatileExample {
  int x = 0;
  volatile boolean v = false;
  public void writer() {
    x = 42;
    v = true;
  }
  public void reader() {
    if (v == true) {
      // 这里 x 会是多少呢?
    }
  }
}

Java 内存模型在 1.5 版本对 volatile 语义进行了增强。怎么增强的呢?答案是一项 Happens-Before 规则。

Happens-Before规则

意思是 前面一个操作的结果对后续操作是可见的

和程序员相关的规则一共有如下六项,都是关于可见性的。

1.程序的顺序性规则

也就是一个线程中,按照程序顺序执行操作,例如下面代码,先执行x = 42再执行v = true

x = 42;
v = true;

2.volatile变量规则

volatile变量的写操作 Happens-Before于这个变量的读操作

3.管程锁定规则

一个锁的解锁 Happens-Before 后续对这个锁的加锁

管程是一种通用的同步原语,在 Java 中指的就是 synchronized,synchronized 是 Java 里对管程的实现。

synchronized (this) { // 此处自动加锁
  // x 是共享变量, 初始值 =10
  if (this.x < 12) {
    this.x = 12; 
  }  
} // 此处自动解锁

4.线程启动规则

线程A启动线程B,线程B能够看到线程A再启动线程B前的操作

5.线程终止规则

这个规则关于线程等待,比如线程A启动线程B,然后调用线程B的join()则,线程B的所有操作都 Happens-Before 于join()操作

6.线程中断规则

对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生,可以通过Thread.interrupted()方法检测到是否有中断发生。

7.对象终结规则

一个对象的初始化完成(构造函数执行结束)先行发生于它的finalize()方法的开始。

Thread B = new Thread(()->{
  // 此处对共享变量 var 修改
  var = 66;
});
// 例如此处对共享变量修改,
// 则这个修改结果对线程 B 可见
// 主线程启动子线程
B.start();
B.join()
// 子线程所有对共享变量的修改
// 在主线程调用 B.join() 之后皆可见
// 此例中,var==66

传递性

A Happens-Before B,B Happens-Before C,则A Happens-Before C

所以按照传递性,之前代码的执行顺序:

  • x = 42
  • v = true (写变量)
  • 读变量v
  • 读变量x

final变量

final 修饰变量时,初衷是告诉编译器:这个变量生而不变,可以可劲儿优化。在1.5版本前,final会有”逸出”的问题。

基本原则

  • 原子性
  • 可见性
  • 有序性。

底层实现

主要是通过内存屏障(memory barrier)禁止重排序的,即时编译器根据具体的底层体系架构,将这些内存屏障替换成具体的 CPU 指令。对于编译器而言,内存屏障将限制它所能做的重排序优化。而对于处理器而言,内存屏障将会导致缓存的刷新操作。比如,对于volatile,编译器将在volatile字段的读写操作前后各插入一些内存屏障。





github: https://github.com/Hikiy
作者:Hiki
创建日期:2019.07.09
更新日期:2019.07.09

(转载本站文章请注明作者和出处 Hiki

Post Directory