文章目录
Java多线程基础 08.JUC包下的AtomicXXX类
AtomicXXX
java.util.concurrent.atomic包下有着许多AtomicXXX命名的类。这些类基于Unsafe的cas方法实现,并对外提供无锁化的原子性操作。
Java类 | 主要作用 |
---|---|
AtomicBoolean | 可以用原子方式更新的 boolean 值。 |
AtomicInteger | 可以用原子方式更新的 int 值。 |
AtomicIntegerArray | 可以用原子方式更新其元素的 int 数组。 |
AtomicIntegerFieldUpdater | 基于反射的实用工具,可以对指定类的指定 volatile int 字段进行原子更新。 |
AtomicLong | 可以用原子方式更新的 long 值。 |
AtomicLongArray | 可以用原子方式更新其元素的 long 数组。 |
AtomicLongFieldUpdater | 基于反射的实用工具,可以对指定类的指定 volatile long 字段进行原子更新。 |
AtomicMarkableReference | AtomicMarkableReference 维护带有标记位的对象引用,可以原子方式对其进行更新。 |
AtomicReference | 可以用原子方式更新的对象引用。 |
AtomicReferenceArray | 可以用原子方式更新其元素的对象引用数组。 |
AtomicReferenceFieldUpdater<T,V> | 基于反射的实用工具,可以对指定类的指定 volatile 字段进行原子更新。 |
AtomicStampedReference | AtomicStampedReference 维护带有整数“标志”的对象引用,可以用原子方式对其进行更新。 |
原子性测试
public class T_AtomicInteger {
AtomicInteger count = new AtomicInteger(0);
void method() {
for (int i = 0; i < 10000; i++)
count.incrementAndGet();
}
public static void main(String[] args) throws InterruptedException {
T_AtomicInteger t = new T_AtomicInteger();
List<Thread> threads = new ArrayList<Thread>();
for (int i = 0; i < 100; i++) {
threads.add(new Thread(t::method, "thread-" + i));
}
for (Thread thread : threads) {
thread.start();
}
for (Thread thread : threads) {
thread.join();
}
System.out.println(t.count);
}
}
AtomicInteger原理解析
AtomicInteger类中有两个重要的静态变量,unsafe和valueOffset。unsafe是sun.misc.Unsafe的实例(更多内容可以看上篇);valueOffset通过Unsafe类计算得出,是AtomicInteger对象内存布局中value属性的偏移量。
java.util.concurrent.atomic.AtomicInteger代码片段
public class AtomicInteger extends Number implements java.io.Serializable {
private static final long serialVersionUID = 6214790243416807050L;
// 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;
/**
* Creates a new AtomicInteger with the given initial value.
*
* @param initialValue the initial value
*/
public AtomicInteger(int initialValue) {
value = initialValue;
}
/**
* Creates a new AtomicInteger with initial value {@code 0}.
*/
public AtomicInteger() {
}
}
通过Unsafe实例和value的偏移量,便可以调用Unsafe.compareAndSwapInt方法来进行原子性的int类型操作。
sun.misc.Unsafe代码片段
public final native boolean compareAndSwapInt(Object object, long valueOffset, int expect, int update);
public final int getAndAddInt(Object object, long valueOffset, int value) {
int oldValue;
do {
oldValue = this.getIntVolatile(object, valueOffset);
} while(!this.compareAndSwapInt(object, valueOffset, oldValue, oldValue + value));
return oldValue;
}
java.util.concurrent.atomic.AtomicInteger代码片段
public final int getAndSet(int newValue) {
return unsafe.getAndSetInt(this, valueOffset, newValue);
}
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
public final boolean weakCompareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}
public final int getAndDecrement() {
return unsafe.getAndAddInt(this, valueOffset, -1);
}
public final int getAndAdd(int delta) {
return unsafe.getAndAddInt(this, valueOffset, delta);
}
public final int incrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
public final int decrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, -1) - 1;
}
AtomicLong原理解析
在介绍Unsafe类时,有提到三个CAS方法,AtomicLong对应的就是compareAndSwapLong。逻辑实现与AtomicInteger一样,便不再赘述。
sun.misc.Unsafe代码片段
public final native boolean compareAndSwapLong(Object object, long valueOffset, long expect, long update);
AtomicObject原理解析
在介绍Unsafe类时,有提到三个CAS方法,AtomicObject对应的就是compareAndSwapObject。逻辑实现与AtomicInteger一样,便不再赘述。
sun.misc.Unsafe代码片段
public final native boolean compareAndSwapObject(Object object, long valueOffset, Object expect, Object update);
AtomicBoolean原理解析
AtomicBoolean类的原理和AtomicInteger也是非常接近的。两者都持有了一个int类型的value属性来存储数值。不同的是,AtomicBoolean对value做了封装,0对应false,1对应true。
java.util.concurrent.atomic.AtomicBoolean代码片段
public class AtomicBoolean implements java.io.Serializable {
private static final long serialVersionUID = 4654671469794556979L;
// setup to use Unsafe.compareAndSwapInt for updates
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset;
static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicBoolean.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
private volatile int value;
/**
* Creates a new {@code AtomicBoolean} with the given initial value.
*
* @param initialValue the initial value
*/
public AtomicBoolean(boolean initialValue) {
value = initialValue ? 1 : 0;
}
/**
* Creates a new {@code AtomicBoolean} with initial value {@code false}.
*/
public AtomicBoolean() {
}
}
AtomicStampedReference原理解析
AtomicStampedReference可以看作是AtomicObject类的增加版。比起AtomicObject,AtomicStampedReference多了一个int类型的stamp属性。通常stamp会作为版本号,来解决CAS的ABA问题。
java.util.concurrent.atomic.AtomicStampedReference代码片段
public class AtomicStampedReference<V> {
private static class Pair<T> {
final T reference;
final int stamp;
private Pair(T reference, int stamp) {
this.reference = reference;
this.stamp = stamp;
}
static <T> Pair<T> of(T reference, int stamp) {
return new Pair<T>(reference, stamp);
}
}
private volatile Pair<V> pair;
/**
* Creates a new {@code AtomicStampedReference} with the given
* initial values.
*
* @param initialRef the initial reference
* @param initialStamp the initial stamp
*/
public AtomicStampedReference(V initialRef, int initialStamp) {
pair = Pair.of(initialRef, initialStamp);
}
public boolean compareAndSet(V expectedReference,
V newReference,
int expectedStamp,
int newStamp)
}