java.util.concurrent.atomic
包下,大致可分为4类。其中底层原理使用的都是由Unsafe
类提供的CAS操作提供。
1. 基本类型原子类
a. AtomicBoolean
b. AtomicInteger
使用的主要参数1
2
3
4
5
6
7
8
9
10
11
12
13
14
15// setup to use Unsafe.compareAndSwapInt for updates
// 使用Unsafe的compareAndSwapInt来进行原子自增操作
private static final Unsafe unsafe = Unsafe.getUnsafe();
// valueOffset表示在当前对象中,value变量的内存偏移量
private static final long valueOffset;
static {
try {
// 静态方法块对valueOffset进行初始化赋值,这个值在赋值后不再变化
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
// AtomicInteger的值
private volatile int value;
主要方法1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22/**
* Atomically increments by one the current value.
*
* @return the updated value
*/
public final int incrementAndGet() {
// 使用Unsafe的getAndAddInt方法进行自增
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
/**
* 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) {
// // 使用Unsafe的compareAndSwapInt进行替换
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
Unsafe的getAndAddInt方法1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16/**
* var1 : 要处理的对象
* var2 : 要处理的数据在var1中的偏置值
* var4 : 要新增到旧值的值
*/
public final int getAndAddInt(Object var1, long var2, int var4) {
// 修改之前的值
int var5;
do {
// 通过var1和var2拿到主内存中要修改值的最新值
var5 = this.getIntVolatile(var1, var2);
// 如果通过CAS替换成功,则退出循环,否则一直自旋
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
return var5;
}
c. AtomicLong
d. 原子类的问题
- ABA问题
- 只能修改单个元素
- 并发量很高时,CAS只能成功一次,大量请求无法更新成功,只能不断自旋,十分消耗CPU自愿,性能很差
针对第一个ABA问题,JUC中提供了2个带版本号的原子类AtomicMarkableReference
和AtomicStampedReference
,每次数据更新后都会更新数据的版本号,用来防止ABA问题发生;
针对只能修改单个元素的问题,JUC提供了AtomicReference
类,它是一个泛型类,可以用来一次性更新多个数据;
针对并发量很高CAS性能变差的问题,JUC提供了LongAdder
类用来提高性能。
2. 引用原子类型
b. AtomicReference
相比基本类型的原子类,AtomicReference
可以针对多个变量进行原子更新。
变量1
2
3
4
5
6
7
8
9
10
11
12
13
14// 使用Unsafe的compareAndSwapObject来进行原子自增操作
private static final Unsafe unsafe = Unsafe.getUnsafe();
// valueOffset表示在当前对象中,value变量的内存偏移量
private static final long valueOffset;
static {
try {
// 静态方法块对valueOffset进行初始化赋值,这个值在赋值后不再变化
valueOffset = unsafe.objectFieldOffset
(AtomicReference.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
private volatile V value;
主要方法1
2
3
4
5
6
7
8
9
10
11/**
* 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);
}1
2
3
4
5/**
* 底层是通过调用JNI实现原子更新
*
*/
public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5);
c. AtomicMarkableReference & AtomicStampedReference
AtomicMarkableReference 和 AtomicStampedReference 的区别是前者判断是否被更新过使用时使用一个boolean变量mark,后者使用一个int类型的stamp字段判断
AtomicMarkableReference
1 | /** |
主要方法1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25/**
* Atomically sets the value of both the reference and mark
* to the given update values if the
* current reference is {@code ==} to the expected reference
* and the current mark is equal to the expected mark.
*
* @param expectedReference the expected value of the reference
* @param newReference the new value for the reference
* @param expectedMark the expected value of the mark
* @param newMark the new value for the mark
* @return {@code true} if successful
*/
public boolean compareAndSet(V expectedReference,
V newReference,
boolean expectedMark,
boolean newMark) {
Pair<V> current = pair;
// 有3
return
expectedReference == current.reference &&
expectedMark == current.mark &&
((newReference == current.reference &&
newMark == current.mark) ||
casPair(current, Pair.of(newReference, newMark)));
}
AtomicStampedReference
1 | private static class Pair<T> { |
1 | /** |
3. 数组原子类
a. AtomicIntegerArray
原子更新int数组中的元素。
常量,变量和static代码块1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20/**
* unsafe持有对象
*/
private static final Unsafe unsafe = Unsafe.getUnsafe();
/**
* 返回数组中第一个元素的偏移地址
*/
private static final int base = unsafe.arrayBaseOffset(int[].class);
private static final int shift;
private final int[] array;
static {
// 返回数组中一个元素占用的大小
int scale = unsafe.arrayIndexScale(int[].class);
// 如果不是2的幂次方,抛异常
if ((scale & (scale - 1)) != 0)
throw new Error("data type scale not a power of two");
//
shift = 31 - Integer.numberOfLeadingZeros(scale);
}
有两个构造方法1
2
3
4
5
6
7
8
9
10
11
12
13
14
15/**
* 创建一个长度为length的原子int数组类对象
*/
public AtomicIntegerArray(int length) {
array = new int[length];
}
/**
* 传入一个int数组,创建一个长度和其相等的原子int数组类对象
* 所有元素都会复制到新的原子int数组类对象内
*/
public AtomicIntegerArray(int[] array) {
// Visibility guaranteed by final field guarantees
this.array = array.clone();
}
常用方法1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22/**
* Returns the length of the array.
*
* @return the length of the array
*/
public final int length() {
return array.length;
}
/**
* Gets the current value at position {@code i}.
*
* @param i the index
* @return the current value
*/
public final int get(int i) {
return getRaw(checkedByteOffset(i));
}
private int getRaw(long offset) {
return unsafe.getIntVolatile(array, offset);
}
getRaw()方法1
2
3
4
5
6
7
8
9
10
11
12
13
private long checkedByteOffset(int i) {
if (i < 0 || i >= array.length)
throw new IndexOutOfBoundsException("index " + i);
return byteOffset(i);
}
private static long byteOffset(int i) {
return ((long) i << shift) + base;
}
private int getRaw(long offset) {
return unsafe.getIntVolatile(array, offset);
}
b. AtomicLongArray
原子更新long数组中的元素。
(3)AtomicReferenceArray
参考文档
[1] 死磕 java原子系列之终结篇
[2] Java魔法类:Unsafe应用解析