jdk5提供了java.util.concurrent包,这个包并行功能强大,工具齐全,其中就包括原子变量atomic
那么我们先说说volatile,volatile可以保证内存的可见性,禁用重排序,但是不能保证操作的原子性,不具备互斥性,那么,什么时候可以用volatile呢?必须同时满足以下三条:
- 不依赖自己:写变量时并不依赖变量的当前值。
- 不依赖别人:变量不与其他状态共同组成invariant。
- 访问变量时,没有其他原因需要加锁。
只解释一下第一条,“不依赖自己的当前值”,举个简单的例子:count++, 这个就叫依赖当前值。为什么要有这样的限制?因为,volatile不保证count++是原子的,即我们所说的“互斥执行”,虽然我们过去的例子都把一条代码当作一个动作,但相信你知道,一条代码在CPU那里多半不会是一条指令,比如count++其实会分解为load-modify-store三个更小的动作,如果这样的操作有多个线程在做,是极易出错的。
原子变量的特点在于其原子性的CAS(compare-and-swap)操作,由此可以完成volatile所不能的“check-and-act”动作,同时它可以保证内存的可见性,“可见性”只不过是其稍带脚支持的功能而已。
Java.util.concurrent中实现的原子操作类包括:AtomicBoolean、AtomicInteger、AtomicLong、AtomicReference。另外其底层就是volatile和CAS 共同作用的结果:
1.首先使用了volatile 保证了内存可见性。
2.然后使用了CAS(compare-and-swap)算法 保证了原子性。
其中CAS算法的原理就是里面包含三个值:内存值A 预估值V 更新值 B 当且仅当 V == A 时,V = B; 否则,不会执行任何操作。
synchronized锁不仅仅有“互斥”的功能,将多步操作加锁保证了原子操作,而且还保证了内存可见性。