关于volatile:深入理解关键字volatile
volatile 关键字的作用是什么?相比于 synchronized 关键字(重量级锁)对性能影响较大,Java提供了一种较为轻量级的可见性和有序性问题的解决方案,那就是应用 volatile 关键字。因为应用 volatile 不会引起上下文的切换和调度,所以 volatile 对性能的影响较小,开销较低。 从并发三要素的角度看,volatile 能够保障其润饰的变量的可见性和有序性,无奈保障原子性(不能保障齐全的原子性,只能保障单次读/写操作具备原子性,即无奈保障复合操作的原子性)。 上面将从并发三要素的角度介绍 volatile 如何做到可见和有序的。 1. volatile 如何实现可见性?什么是可见性?可见性指当多个线程同时访问共享变量时,一个线程对共享变量的批改,其余线程能够立刻看到(即任意线程对共享变量操作时,变量一旦扭转所有线程立刻能够看到)。 1.1 可见性例子/** * volatile 可见性例子 * @author 单程车票 */public class VisibilityDemo { // 结构共享变量 public static boolean flag = true;// public static volatile boolean flag = true; // 如果应用volatile润饰则能够终止循环 public static void main(String[] args) { // 线程1更改flag new Thread(() -> { // 睡眠3秒确保线程2启动 try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) {e.printStackTrace();} // 批改共享变量 flag = false; System.out.println("批改胜利,以后flag为true"); }, "one").start(); // 线程2获取更新后的flag终止循环 new Thread(() -> { while (flag) { } System.out.println("获取到批改后的flag,终止循环"); }, "two").start(); }}不应用 volatile 润饰 flag 变量时,运行程序会进入死循环,也就是说线程1对 flag 的批改并没有被线程2读到,也就是说这里的flag并不具备可见性。应用 volatile 润饰 flag 变量时,运行程序会终止循环,打印提醒语句,阐明线程2读到了线程1批改后的数据,也就是说被 volatile 润饰的变量具备可见性。*1.2 volatile 如何保障可见性?被 volatile 润饰的共享变量 flag 被一个线程批改后,JMM(Java内存模型)会把该线程的CPU内存中的共享变量 flag 立刻强制刷新回主存中,并且让其余线程的CPU内存中的共享变量 flag 缓存生效,这样当其余线程须要拜访该共享变量 flag 时,就会从主存获取最新的数据。 ...