===== java 内存模型 =====
* 一个进程有一个内存块(叫主内存,所有变量都定义在这个内存中)
* 进程下有多个线程,每个线程有自己的工作内存,该内存中所有变量都拷贝自主内存
* 线程只能与自己的工作内存通信,线程间数据通信必须通过主内存
{{:pasted:20160216-193322.png}}
===== 可见性和原子性=====
==== 可见性 ====
可见性指一个线程对某个变量更改后,是否对其他线程可见
=== 可见的必要条件 ===
- 线程A在自己的工作内存中对变量V做了修改
- 把修改后的变量V同步到主内存
- 线程B重主内存重新加载变量V (这时线程B才能看到线程A做的修改)
==== 原子性 ====
某个时刻,只允许一个线程修改某个共享变量
===== final 关键字 =====
final关键字修饰的变量在各个线程间是可见的
* final关键字修饰的变量是不可变的,所以在各个线程的工作内存中存的副本值都一样,不存在各个线程不一致的问题,所以在各个线程中都是可见的
===== volatile 关键字 =====
==== volatile的可见性 ====
volatile执行过程
- 每次读取共享变量时,强制从主内存读取最新的副本到工作内存
- 在工作内存中修改共享变量
- 共享变量修改后,强制刷新回主内存(所以每个线程在访问时候会读到最新值)
==== volatile 的原子性 ====
* 虽然每次都能读取到最新值,但是不能保证原子性。
* 因为volatile关键字允许多个线程同时修改该变量。当多个线程同时修改时,依然会导致丢失更新(如下情况)
* **多个线程同时对volatile 关键字修饰的变量count 做自增操作**
- 假如在某一时刻线程A同时读到count的值是5,正准备+1的时候,线程切换到B
- 线程B读取count的值为5,线程切换到A
- 线程A更新count值为6,并写回主内存,切换到线程B
- 线程B更新count值为6,并写回主内存 (然而丢失了一次更新)
可见要做到原子性,必须每个时刻只能有一个线程对该变量进行更新
volatile 不能像synchronized做到原子性,但是他的性能相对synchronized较高。那volatile可以在哪些场景下使用呢?当对变量只读,且修改时不依赖原值的情况下可以使用
===== synchronized 关键字 =====
synchronized既能保证可见性,又能保证原子性
synchronized执行过程
- 获得互斥锁(加锁后,只有该线程有权执行,其他线程必须等待)
- 清空工作内存
- 从主内从拷贝最新副本到工作内存
- 执行代码
- 将更新后的值刷新回主内存
- 释放互斥锁