===== 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执行过程 - 获得互斥锁(加锁后,只有该线程有权执行,其他线程必须等待) - 清空工作内存 - 从主内从拷贝最新副本到工作内存 - 执行代码 - 将更新后的值刷新回主内存 - 释放互斥锁