前置概念
- 指令重排:JVM 为了优化指令、提高运行速度,在不影响单线程执行结果的前提下,会对代码进行重排。
- 内存可见性:每个线程在获取锁之后,会在自己的工作内存中操作共享变量,操作完成之后将工作内存中的副本写回内存,在此过程中共享变量的变化对其是不可见的。这样做也是为了提高效率。
volatile 关键字的作用
- 防止指令重排;
- 线程中的每一个操作 happens-before 这个线程中在程序顺序中后面出现的每一个操作
- 对监视器的解锁 happens-before 同一监视器上的所有后续锁定
- 对 volatile 字段的写 happens-before 同一 volatile 的每一个后续读
- 对一个线程的 Thread.start() 调用 happens-before 在启动的线程中的所有操作
- 线程中的所有操作 happens-before 从这个线程的 Thread.join() 成功返回的所有其他线程
- 保证每次访问变量都会刷新。
保证 volatile 字段的读写直接在主存而不是寄存器或者本地处理器缓存中进行,并且代表线程对 volatile 变量进行的这些操作是按线程要求的顺序进行的。
这样 volatile 就提供了一个轻量级的锁机制。
注意
- 已经用 synchronize 关键字加锁的变量不需要 volatile 修饰。
- 非原子操作如
i++
,需要用 synchronize 关键字同步。