目录
综述
JDK从1.5开始提供了java.util.concurrent.atomic包。
通过包中的原子操作类能够线程安全地更新一个变量。
包含4种类型的原子更新方式:基本类型、数组、引用、对象中字段更新。
atomic包中的原子操作类基本上内部都是使用Unsafe类实现的,原子更新的实质其实就是获取内存偏移地址,对地址中的变量进行更新。
1.原子更新基本类型类
atomic包内包含AtomicBoolean、AtomicInteger、AtomicLong这3个类,以下以AtomicInteger进行讲解。
AtomicInteger是如何实现原子操作的?
是使用Unsafe类实现的,而Unsafe实现原子操作的原理是通过得到变量相对于对象示例的内存偏移地址,更新内存地址内的变量值。
下面是摘录的AtomicInteger的部分源码。
/** * Atomically increments by one the current value. * * @return the previous value */ public final int getAndIncrement() { return unsafe.getAndAddInt(this, valueOffset, 1); } /** * Atomically decrements by one the current value. * * @return the previous value */ public final int getAndDecrement() { return unsafe.getAndAddInt(this, valueOffset, -1); } /** * 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); } /** * Atomically increments by one the current value. * * @return the updated value */ public final int incrementAndGet() { return unsafe.getAndAddInt(this, valueOffset, 1) + 1; } /** * Atomically decrements by one the current value. * * @return the updated value */ public final int decrementAndGet() { return unsafe.getAndAddInt(this, valueOffset, -1) - 1; } /** * Atomically adds the given value to the current value. * * @param delta the value to add * @return the updated value */ public final int addAndGet(int delta) { return unsafe.getAndAddInt(this, valueOffset, delta) + delta; }
2.原子更新数组
atomic包内包含AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray这3个类,以下以AtomicIntegerArray进行讲解。
AtomicIntegerArray是如何实现原子操作的?
是使用Unsafe类实现的,而Unsafe实现原子操作的原理是通过得到变量相对于数组的内存偏移地址,更新内存地址内的变量值。
下面是摘录的AtomicIntegerArray的部分源码。
/** * Atomically increments by one the element at index {@code i}. * * @param i the index * @return the previous value */ public final int getAndIncrement(int i) { return getAndAdd(i, 1); } /** * Atomically decrements by one the element at index {@code i}. * * @param i the index * @return the previous value */ public final int getAndDecrement(int i) { return getAndAdd(i, -1); } /** * Atomically adds the given value to the element at index {@code i}. * * @param i the index * @param delta the value to add * @return the previous value */ public final int getAndAdd(int i, int delta) { return unsafe.getAndAddInt(array, checkedByteOffset(i), delta); } /** * Atomically increments by one the element at index {@code i}. * * @param i the index * @return the updated value */ public final int incrementAndGet(int i) { return getAndAdd(i, 1) + 1; } /** * Atomically decrements by one the element at index {@code i}. * * @param i the index * @return the updated value */ public final int decrementAndGet(int i) { return getAndAdd(i, -1) - 1; } /** * Atomically adds the given value to the element at index {@code i}. * * @param i the index * @param delta the value to add * @return the updated value */ public final int addAndGet(int i, int delta) { return getAndAdd(i, delta) + delta; }
3.原子更新引用
使用AtomicInteger只能原子更新一个变量,如果要原子更新多个变量,就需要将多个变量封装起来,原子更新对象引用。
atomic包内包含AtomicReference、AtomicReferenceFieldUpdater、AtomicUpdater这3个类,以下以AtomicIntegerArray进行讲解。
下面是摘录的AtomicReference的部分源码。
/** * 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(V expect, V update) { return unsafe.compareAndSwapObject(this, valueOffset, expect, update); } /** * Atomically sets to the given value and returns the old value. * * @param newValue the new value * @return the previous value */ @SuppressWarnings("unchecked") public final V getAndSet(V newValue) { return (V)unsafe.getAndSetObject(this, valueOffset, newValue); }
4.原子更新字段类
用于更新类里的某个字段。
atomic包内包含AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicStampedReference这3个类。
AtomicStampedReference 将整数值与引用关联起来,可以用于原子地更新数据和数据的版本号,可以解决CAS的ABA问题。