Volatile 与 Atomic

89 阅读2分钟

Volatile

对于普通的共享变量来讲,线程 A 将其修改为某个值发生在线程 A 的本地内存中,此时还未同步到主内存中去;而线程 B 已经缓存了该变量的旧值,所以就导致了共享变量值的不一致。解决多线程中的不可见性问题,较粗暴的方式就是加锁,但是太重量级了,比较合理的方式其实就是volatile。

Volatile 原理

Volatile 可以保证线程可见性且提供了一定的有序性,但是无法保证原子性。在 JVM 底层 Volatile 是采用内存屏障来实现的。加入 Volatile 关键字时,会多出一个 lock 前缀指令,lock前缀指令实际上相当于一个内存屏障,内存屏障会提供3个功能:

  1. 它确保指令重排序时不会把其后面的指令排到内存屏障之前的位置,也不会把前面的指令排到内存屏障的后面;即在执行到内存屏障这句指令时,在它前面的操作已经全部完成;
  2. 它会强制将对缓存的修改操作立即写入主存;
  3. 如果是写操作,它会导致其他 CPU 中对应的缓存行无效。

Atomic

JDK1.5之后出的,这个包提供了一系列原子类(原子性是指一个操作是不可分割的,要么全部完成,要么全部不完成。)。用于实现线程安全的整数自增和自减操作。这些类可以保证多线程环境下,当某个线程在执行 Atomic的方法时,不会被其他线程打断,而别的线程就像自旋锁一样,一直等到该方法执行完成,才由 JVM 从等待队列中选择一个线程执行。

Atomic 原理

Atomic使用了 Volatile 关键字来保证可见性,以及 CAS 操作来实现原子性。CAS 操作的基本思想是,在进行自增或自减操作之前,先比较当前值是否与期望值相等,如果相等,则将当前值修改为新值。如果当前值与期望值不相等,则说明其他线程已经修改了该值,当前线程需要重新读取该值并尝试修改。