我看 JAVA 之 并发编程【四】线程安全与 JMM
我看 JAVA 之 并发编程【四】线程安全与 JMM
线程安全
概念
三大特性
原子性
即一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。
JDK64 位中对基本数据类型的变量的读取和赋值操作是原子性操作,即这些操作是不可被中断的,要么执行,要么不执行。
y =10 是原子的。
y=x 就不是原子的:有两个步骤 1,读取 x 值;2,赋值给 y
i++也不是原子的,大家可以思考下为什么。
通过如下三种方式可以保障原子性:
Synchronized
Lock
Atomic 原子工具类
可见性
指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。
通过如下三种方式可以保障可见性:
Synchronized
volatile
Lock
有序性
即程序执行的顺序按照代码的先后顺序执行。当然可能会遇到编译器重排,指令重排等,但不影响计算结果。
通过如下三种方式可以保障有序性:
Synchronized
volatile
Lock
JMM
体系结构
JMM 定义了 8 个同步操作,如下:
同步流程
happens-before 原则
Java 内存模型具备一些先天的“有序性”,即不需要通过任何手段就能够得到保证的有序性,这个通常也称为 happens-before 原则。如果两个操作的执行次序无法从 happens-before 原则推导出来,那么它们就不能保证它们的有序性,虚拟机可以随意地对它们进行重排序。
下面就来具体介绍下 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()规则:Thread 对象的 start()方法先行发生于此线程的每个一个动作。
(6)Join()规则:如果线程 A 执行操作 ThreadB.join()并成功返回,那么线程 B 中的任意操作 happens-before 于线程 A 从 ThreadB.join()操作成功返回。
(7)程序中断规则:对线程 interrupted()方法的调用先行于被中断线程的代码检测到中断时间的发生。
(8)对象 finalize 规则:一个对象的初始化完成(构造函数执行结束)先行于发生它的 finalize()方法的开始。
volatile
volatile 关键字保证了变量的内存可见性以及有序性。简单来说就是通过缓存一致性协议(MESI)和内存屏障来实现。
评论