JUC中的原子类主要有以下几类:
- 原子整数
- 原子引用
- 原子数组
- 原子更新器
- 原子累加器
原子整数
原子整数主要有AtomicBoolean、AtomicInteger、AtomicLong,三个类中都是通过value属性来存储值,其中AtomicInteger和AtomicLong方法几乎一样,所以这里只介绍一个就好了。
private volatile int value;
AtomicBoolean
两个构造方法,无参构造方法value值就是默认值0,有参构造方法value值就是传入的参数。
public AtomicBoolean() {
}
public AtomicBoolean(int initialValue) {
value = initialValue;
}
get方法获取当前值,因为value是int类型,所以返回的是value!=0
public final boolean get() {
return value != 0;
}
获取旧值并设置新值,这是一个原子方法,保证了获取并设置新值的过程不会被打断
public final boolean getAndSet(boolean newValue)
AtomicInteger/AtomicLong
AtomicInteger和AtomicLong方法一样,只是类型一个是int一个是long而已
同样地两个构造方法,无参构造方法value值就是默认值0,有参构造方法value值就是传入的参数。
public AtomicInteger() {
}
public AtomicInteger(int initialValue) {
value = initialValue;
}
获取旧值并自增1,等同于i++
public final int getAndIncrement()
获取旧值并自减1,等同于i--
public final int getAndDecrement()
先自增1再获取新值,等同于++i
public final int incrementAndGet()
先自减1再获取新值,等同于--i
public final int decrementAndGet()
先加delta再获取新值
public final int addAndGet(int delta)
先获取旧值再加delta
public final int getAndAdd(int delta)
先获取旧值,再根据指定方法进行更新,不局限于加减法,可以是任何复杂计算
public final int getAndUpdate(IntUnaryOperator updateFunction)
// 对i乘以10
AtomicInteger i = new AtomicInteger(1);
i.getAndUpdate(v -> v * 10)
先根据指定方法进行更新,再获取新值,使用方法同getAndUpdate
public final int updateAndGet(IntUnaryOperator updateFunction)
原子引用
原子引用主要有AtomicReference、AtomicStampedReference、AtomicMarkableReference三个类。
AtomicReference
通过一个泛型类型value来存储值,所以可以是任意引用类型,调用有参构造方法传入初始值,调用无参构造初始值就是null
private volatile V value;
public AtomicReference(V initialValue) {
value = initialValue;
}
public AtomicReference() {
}
get方法获取当前值
public final V get()
先获取旧值再设置新值
public final V getAndSet(V newValue)
先获取旧值,然后通过一个函数式接口中的方法结果设置新值
public final V getAndUpdate(UnaryOperator<V> updateFunction)
先执行操作来更新值,然后再获取新值
public final V updateAndGet(UnaryOperator<V> updateFunction)
AtomicStampedReference
上一篇文章 Java并发编程之CAS原理 中提到ABA问题的解决方法,就可以通过AtomicStampedReference来实现
通过内部类Pair来存储两个值,一个是引用的值reference,一个是int类型版本号stamp,每次修改都可以设置不同的值
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);
}
}
}
构造方法对引用值和版本号进行初始化
public AtomicStampedReference(V initialRef, int initialStamp) {...}
比较旧值和期待的值是否相等,并且比较版本号和期待的版本号是否相等,两个都相等才会设置新值和新版本号
public boolean compareAndSet(V expectedReference,
V newReference,
int expectedStamp,
int newStamp)
AtomicMarkableReference
如果在更新引用时并不关心中间被修改过多少次,只关心是否被更改过,那么只需要设置一个标记就可以了,AtomicMarkableReference就可以解决这种情况。
同样也是通过一个内部类来存储两个值,不过这里存储的是引用值和boolean类型的标记
public class AtomicMarkableReference<V> {
private static class Pair<T> {
final T reference;
final boolean mark;
...
}
...
}
构造方法对引用值和标记值进行初始化
public AtomicMarkableReference(V initialRef, boolean initialMark) {...}
比较旧值和期待的值是否相等,并且比较旧的标记和期待的标记是否相等,两个都相等才会设置新值和新标记
public boolean compareAndSet(V expectedReference,
V newReference,
boolean expectedMark,
boolean newMark)