AtomicInteger 可以看做 Integer 类的原子操作工具类。在 java.util.concurrent.atomic 包下,在一些使用场合下可以取代加锁操作提高并发性。接下来就从几个方面来介绍:
1. 原子性和 CAS。
2.CPU 底层实现原理。
3.atomic 包介绍。
4. 源码分析。
原子性和 CAS
原子性就是指某一个操作是不可拆分的,是一个整体必须要一次性全部执行完成要么就不执行。
CAS 是 Compare And Swap(比较并交换)。意思是当你要更新某个值的时候先要检查这个变量的当前值是不是改变了,如果改变了就不能更新,没改变就可以更新。
atomic 包介绍
类的小工具包,支持在单个变量上解除锁的线程安全编程。此包中的类可将 volatile 值、字段和数组元素的概念扩展到那些也提供原子条件更新操作的类,其形式如下:
- boolean compareAndSet(expectedValue, updateValue);
如果此方法(在不同的类间参数类型也不同)当前保持 expectedValue,则以原子方式将变量设置为 updateValue,并在成功时报告 true。此包中的类还包含获取并无条件设置值的方法,以及以下描述的较弱条件的原子更新操作 weakCompareAndSet。
原子访问和更新的内存效果一般遵循以下可变规则:
设计原子类主要用作各种构造块,用于实现非阻塞数据结构和相关的基础结构类。compareAndSet 方法不是锁的常规替换方法。仅当对象的重要更新限定于 变量时才应用它。原子类不是 java.lang.Integer 和相关类的通用替换方法。它们 定义诸如 hashCode 和 compareTo 之类的方法。
源码举例分析
AtomicInteger 继承结构:
-
---
------java.util.concurrent.atomic.AtomicInteger
还实现了 java.io.Serializable 以便序列化使用,然后是字段的定义和初始化:
Unsafe 里面定义了许多 Native 方法,通过 JNI 调用。value 就是 AtomicInteger 代表的值,这里用 volatile 修饰用以保证 value 的可见性。
- //源码 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;
AtomicInteger 大概实现了 20 个左右的 public 方法,下面举几个有代表性的来分析:
1.get 方法是用来获取当前最新的 value。方法用 final 修饰是为了更进一步的保证线程安全。
- /**
- * Gets the current value.
- *
- * @return the current value
- */
- public final int get() {
- return value;
- }
2.set 方法是把 value 更新为一个新值。也是用 final 修饰。
- /**
- * Sets to the given value.
- *
- * @param newValue the new value
- */
- public final void set(int newValue) {
- value = newValue;
- }
3.lazySet 方法和 set 方法不同之处在于可以延时设置,就是在最后才设定新值。
- /**
- * Eventually sets to the given value.
- *
- * @param newValue the new value
- * @since 1.6
- */
- public final void lazySet(int newValue) {
- unsafe.putOrderedInt(this, valueOffset, newValue);
- }
4.getAndSet 方法是把新值设置为当前值然后返回旧值。
- /**
- * Atomically sets to the given value and returns the old value.
- *
- * @param newValue the new value
- * @return the previous value
- */
- public final int getAndSet(int newValue) {
- return unsafe.getAndSetInt(this, valueOffset, newValue);
- }
5.compareAndSet 方法是首先比较当前值与期望值,相同才更新到新值。如果更新成功则返回 true,否则返回 false。
- /**
- * Atomically sets the value to the given updated value
- * if the current value {@code ==} the expected value.
- *
- * @param expect the expected value
- * @param update the new value
- * @return {@code true} if successful. False return indicates that
- * the actual value was not equal to the expected value.
- */
- public final boolean compareAndSet(int expect, int update) {
- return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
- }
6.getAndIncrement 方法是原子的把原值加一并且返回旧值。getAndDecrement 类似。
- /**
- * Atomically increments by one the current value.
- *
- * @return the previous value
- */
- public final int getAndIncrement() {
- return unsafe.getAndAddInt(this, valueOffset, 1);
- }
7.getAndAdd 方法是把原值加上某个值,并返回以前的值。
- /**
- * Atomically adds the given value to the current value.
- *
- * @param delta the value to add
- * @return the previous value
- */
- public final int getAndAdd(int delta) {
- return unsafe.getAndAddInt(this, valueOffset, delta);
- }
8.incrementAndGet 方法是把原值加一后返回新值。decrementAndGet 类似。
- /**
- * Atomically increments by one the current value.
- *
- * @return the updated value
- */
- public final int incrementAndGet() {
- return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
- }
9.getAndUpdate 方法是根据一个定义的操作符来把当前值当第一个参数,传入的参数当做第二个参数更新 value,返回旧值。updateAndGet 是返回新值。 使用自旋的方式,调用了 compareAndSet 方法,只有返回了 true 才结束。
- /**
- * Atomically updates the current value with the results of
- * applying the given function, returning the previous value. The
- * function should be side-effect-free, since it may be re-applied
- * when attempted updates fail due to contention among threads.
- *
- * @param updateFunction a side-effect-free function
- * @return the previous value
- * @since 1.8
- */
- public final int getAndUpdate(IntUnaryOperator updateFunction) {
- int prev,
- next;
- do {
- prev = get();
- next = updateFunction.applyAsInt(prev);
- } while (! compareAndSet ( prev , next ));
- return prev;
- }
以上这些方法都是原子操作。
来源: