经过volatile和synchronize关键字的底层原理的洗礼,不知道你是否有一种感觉,要想弄明白它们的原理是一个非常难的过程。为什么费这么大的力气要弄明白这些并发基础知识呢?
其实是为了之后更好的掌握并发组件、并发集合这些内容。JDK中的juc(并发包)的知识大体可以分为如下几块:
并发基础中除了volatile、synchronied、线程状态变化之外,还有很重要的两个知识CAS和AQS。而其他并发组件和集合都是基于这些知识来实现的工具而已。
这一节我们通过Atomic类来学习下它的底层原理,实际它的底层通过CAS+volatile的原理来实现的。我们来具体看看:
- JDK中的CAS如何实现的?又是如何应用在Atomic中的?
- CAS的自旋性能问题怎么优化?
- CAS的ABA问题怎么解决?
在Java代码中,CAS是如何应用在Atomic中的?
在Java代码中,CAS是如何应用在Atomic中的?
之前学习synchronized的时候,就接触过CAS。CAS一般称作Compare And Swap操作。操作流程如下:
上面CAS操作简单描述可以如下:当更新一个值从E->V时,更新的时候需要读取E最新的值N,如果发生了变化,也就是当E!=N,就不会更新成功,重新尝试,否则更新值成功,变为V。
来看一个Demo:
private static AtomicInteger j = new AtomicInteger(0);
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(() -> {
System.out.println(AtomicIntegerDemo.j.incrementAndGet());
}).start();
}
}
这段程序有10个线程,它们可能同时更新J的值。但是输出结果是按顺序输出了0到10的数字。这是因为在AtomicInteger底层,每个线程的更新都是CAS操作,它保证了多线程修改同一个值的原子性。
首先你可以先看一下AtomicInteger 整体脉络:
根据之前分析源码的思想,先脉络后细节,你应该可以看出,它核心脉络就是一个Unsafe对象,int的value。如下
public class AtomicInteger extends Number implements java.io.Serializable {
// setup to use Unsafe.compareAndSwapInt for updates
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset;
static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
private volatile int value;
}
核心变量:
<