From 97ca9ab198a459eed9be8e1af4a06fca4cd18d1f Mon Sep 17 00:00:00 2001 From: CyC2018 <1029579233@qq.com> Date: Tue, 13 Mar 2018 10:35:41 +0800 Subject: [PATCH] auto commit --- notes/Java 并发.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/notes/Java 并发.md b/notes/Java 并发.md index d5963911..23fc6d1b 100644 --- a/notes/Java 并发.md +++ b/notes/Java 并发.md @@ -20,6 +20,9 @@ * [1. 阻塞](#1-阻塞) * [2. 中断](#2-中断) * [线程状态转换](#线程状态转换) +* [volatile](#volatile) + * [1. 内存可见性](#1-内存可见性) + * [2. 禁止指令重排](#2-禁止指令重排) * [内存模型](#内存模型) * [1. 硬件的效率与一致性](#1-硬件的效率与一致性) * [2. Java 内存模型](#2-java-内存模型) @@ -423,6 +426,26 @@ interrupted() 方法在检查完中断状态之后会清除中断状态,这样 - LockSupport.parkNanos() 方法 - LockSupport.parkUntil() 方法 +# volatile + +保证了内存可见性和禁止指令重排,没法保证原子性。 + +## 1. 内存可见性 + +普通共享变量被修改之后,什么时候被写入主存是不确定的。 + +volatile 关键字会保证每次修改共享变量之后该值会立即更新到内存中,并且在读取时会从内存中读取值。 + +synchronized 和 Lock 也能够保证内存可见性。它们能保证同一时刻只有一个线程获取锁然后执行同步代码,并且在释放锁之前会将对变量的修改刷新到主存当中。不过只有对共享变量的 set() 和 get() 方法都加上 synchronized 才能保证可见性,如果只有 set() 方法加了 synchronized,那么 get() 方法并不能保证会从内存中读取最新的数据。 + +## 2. 禁止指令重排 + +在 Java 内存模型中,允许编译器和处理器对指令进行重排序,重排序过程不会影响到单线程程序的执行,却会影响到多线程并发执行的正确性。 + +volatile 关键字通过添加内存屏障的方式来进制指令重排,即重排序时不能把后面的指令放到内存屏障之前。 + +可以通过 synchronized 和 Lock 来保证有序性,它们保证每个时刻只有一个线程执行同步代码,相当于是让线程顺序执行同步代码,自然就保证了有序性。 + # 内存模型 ## 1. 硬件的效率与一致性