getAndSet - 设新值,返旧值
因为 value 是 volatile 变量,所以对 value 的 read/write 具备 happens-before 关系,所以一个很容易想到的实现为:
AtomicInteger counter = new AtomicInteger(); int oldV = counter.get(); counter.set(10);
但该实现是错的,因为 counter.get() 与 counter.set(10) 之间可能插入其他线程的 set,所以 oldV 不能保证是 set(10) 执行时的 value 值,当然通过锁将 get 与 set(10) 变成原子操作可以满足需求,但我们使用 AtomicInteger 就是为了避免使用锁,所以也不能这么做.
于是有了getAndSet:
将 set 和 get 合并成一个原子操作,同时避免使用锁,依旧借助 unsafe 实现。
基本的运算操作
自增
- 以原子方式将当前值增加一(i++)
- 以原子方式将当前值增加一(++i)
自减
- 以原子方式将当前值减一(i–)
- 以原子方式将当前值减一(–i)
- 都是基于 Unsafe.getAndAddInt 实现的,该方法实现 value 加操作,且返回旧值。
任意值的加减
CAS 操作
compareAndSet
getAndSet 无脑更新 value ,并发场景下不会一直如此简单,有时要求 value 满足特定条件时才设置,这是非常典型的原子复合操作
检查某条件是否成立
根据条件成功、失败执行不同操作
在业务代码中,这种操作一般用锁实现,但 AtomicInteger 原生提供的 compareAndSet 无锁完美解决.
只有 value 的当前值等于 expect 时,才把 value 设置为 update,同时如果设置成功则返回 true,否则返回 false。
借助返回值可以检测方法的执行结果,因此可以在循环操作中不断执行 compareAndSet,直到成功,在线程池的源码中,很多方法都是这种套路。
weakCompareAndSet
- 弱化版compareAndSet,可能会虚假地失败,并且不提供排序保证,因此,很少是compareAndSet的适当替代方法,JDK8源码中未曾使用过它,因为二者在 Java 源码层次是一模一样的.
总结
AtomicIntger 的关键是 compareAndSet 方法,基于它可实现乐观的无锁算法.其妙用在 线程池中有着淋漓尽致地体现