03Java内存模型(Java并发编程的艺术)

1.Java内存模型基础

1.1 Java内存模型的抽象结构

在Java中,所有实例、静态域和数组元素都存储在堆内存中,堆内存在线程之间共享。局部变量、方法定义参数、异常处理器参数不会在线程中共享。

Java线程之间的通信由Java内存模型(Java Memory Model,简称:JMM)控制,JMM决定一个线程共享变量的写入核实对其他线程可见,即通过控制主内存和每个线程的本地内存之间的交互。抽象的结构示意图如下所示:

Java内存模型的抽象结构示意图


1.2 从源码到指令序列的重排序

1.2.1 定义

(1)编译器优化的重排序;在不改变单线程程序语义的前提下;

(2)指令级并行的重排序;在不存在数据依赖性的前提下;

(3)内存系统的重排序;

1.2.2 数据依赖性(单个处理器和单个线程)

如果两个操作访问同一个变量,且这两个操作中有一个为写操作,辞职这两个操作之间存在数据依赖性。

(1)写后读,写一个变量后,再读这个变量

(2)写后写,写一个变量后,再写这个变量

(3)读后写,读一个变量后,再写这个变量

1.2.3 as-if-serial语义

不管怎么重排序,(单线程)程序的执行结果不能改变。

1.3 happens-before

(1)程序顺序规则:一个线程中的每个操作,happens-before于该线程中的任意后续操作;

(2)监视器锁规则:对一个锁的解锁,happens-before于随后对这个锁的加锁;

(3)volatile变量规则:对于一个volatile域的写,happens-before与任意后续对这个volatile域的读;

(4)传递性:如果A happens-before B,且B happens-before C,那么A happens-before C。

(5)start规则:如果线程A执行操作ThreadB.start(),那么A线程的ThreadB.start()操作happens-before于线程B中的任意操作。

(6)join规则:如果线程A执行操作ThreadB.join()并成功返回,那么线程B中的任意操作happens-before于线程A从ThreadB.join()操作成功返回。

2. volatile的内存语义

2.1 volatile特性

(1)可见性

对一个volatile变量的读,总是能看到(任意线程)对这个volatile变量最后的写入。

(2)原子性

对任意单个volatile变量的读/写具有原子性,但是类似volatile++这种复合操作不具有原子性。

2.2 volatile内存语义的实现

(1)当第二个操作是volatile写时,不管第一个操作是什么,都不能重排序。

(2)当第一个操作是volatile读时,不管第二个操作是什么,都不能重排序。

(3)当第一个操作是volatile写,第二个操作是volatile读时,不能重排序。

2.3 volatile使用场景

参考:正确使用 Volatile 变量

3 final的内存语义

3.1 final域的重排序规则

(1)在构造函数内对一个final域的写入,与随后将把这个被构造对象的引用复制给一个变量,这两个操作之间不能重排序;禁止把final域的写重排序到构造函数外。

(2)初次读一个包含final域的对象的应用,与随后初次读这个final域,这两个操作之间不能重排序;

4 创建对象的步骤

(1)分配对象的内存空间

(2)初始化对象

(3)设置变量指向刚分配的内存地址

你可能感兴趣的:(03Java内存模型(Java并发编程的艺术))