简介
JDK的atomic包中提供了一些简单原子操作类,基本上都是基于volatile+CAS封装,既保证了性能又保证了线程安全。例如平时经常用到的i++多线程场景就可以用AtomicInteger去解决,有ABA强需求的需要谨慎使用,后面会单独写一篇。
AtomicInteger 类
public class AtomicInteger extends Number
implements java.io.Serializable
AtomicInteger 属性
// 使用volatile修饰的值属性
private volatile int value;
// 内存操作不安全类
private static final Unsafe unsafe = Unsafe.getUnsafe();
// value偏移量
private static final long valueOffset;
前面有人问到CAS为什么一定要和volatile配合使用,这里顺便解释一下。首要要明白Java中变量赋值过程:
第一步lock:作用于主内存,把变量标识为线程独占状态。
第二步unlock:作用于主内存,解除独占状态。
第三步read:作用主内存,把一个变量的值从主内存传输到线程的工作内存。
第四步load:作用于工作内存,把read操作传过来的变量值放入工作内存的变量副本中。
第五步use:作用工作内存,把工作内存当中的一个变量值传给执行引擎。
第六步assign:作用工作内存,把一个从执行引擎接收到的值赋值给工作内存的变量。
第七步store:作用于工作内存的变量,把工作内存的一个变量的值传送到主内存中。
第八步write:作用于主内存的变量,把store操作传来的变量的值放入主内存的变量中。
volatile 特性一:保持内存可见性。
内存可见就是说read、load、use动作必须连续出现,assign、store、write动作必须连续出现。所以,使用volatile变量能够保证每次读取前必须先从主内存刷新最新的值,每次写入后必须立即同步回主内存当中。也就是说,volatile关键字修饰的变量看到的随时是自己的最新值。线程1中对变量v的最新修改,对线程2是可见的。
volatile 特性二:防止指令重排
Java内存模型也是基于Happens-Before内存模型,在Happens-Before内存模型中会出现指令重排序问题。Happens-Before内存模型维护了几种Happens-Before规则,程序顺序规则最基本的规则。程序顺序规则的目标对象是一段程序代码中的两个操作A、B,其保证此处的指令重排不会破坏操作A、B在代码中的先后顺序,但与不同代码甚至不同线程中的顺序无关。
Java为了实现volatile的内存语义,编译器在生成字节码时,会在指令序列中插入内存屏障来禁止特定类型的处理器重排序。然而,对于编译器来说,发现一个最优布置来最小化插入屏障的总数几乎不可能,为此,Java内存模型采取保守策略。
在每个volatile写操作的前面插入一个StoreStore屏障。
在每个volatile写操作的后面插入一个StoreLoad屏障。
在每个volatile读操作的后面插入一个LoadLoad屏障。
在每个volatile读操作的后面插入一个LoadStore屏障。
如果CAS修改的变量不是volatile修饰的,那么在可能修改的只是一个线程工作内存值,也有可能是被指令重排的旧值。
AtomicInteger 静态加载初始化
// 初始化value偏移量
static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
AtomicInteger 构造函数
// 初始化时指定值
public AtomicInteger(int initialValue) {
value = initialValue;
}
// 是用int默认值
public AtomicInteger() {
}
AtomicInteger 普通方法
// 获取值
public final int get() {
return value;
}
// 直接覆盖值
public final void set(int newValue) {
value = newValue;
}
// 返回int类型值
public int intValue() {
return get();
}
// 返回long类型值
public long longValue() {
return (long)get();
}
// 返回float类型值
public float floatValue() {
return (float)get();
}
// 返回double类型值
public double doubleValue() {
return (double)get();
}
AtomicInteger 原子操作
// 设置新值(因为这里只是写所以顺序写就行)
public final void lazySet(int newValue) {
unsafe.putOrderedInt(this, valueOffset, newValue);
}
// 设置新值返回旧值
public final int getAndSet(int newValue) {
return unsafe.getAndSetInt(this, valueOffset, newValue);
}
// CAS修改值
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
// CAS修改值
public final boolean weakCompareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
// 返回原值,value加1(先返回再加1)
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}
// 返回原值,value减1(先返回再减1)
public final int getAndDecrement() {
return unsafe.getAndAddInt(this, valueOffset, -1);
}
// 返回原值,value加delta
public final int getAndAdd(int delta) {
return unsafe.getAndAddInt(this, valueOffset, delta);
}
// 返回加1后的值
public final int incrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
// 返回减1后的值
public final int decrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, -1) - 1;
}
// 返回value加delta的值
public final int addAndGet(int delta) {
return unsafe.getAndAddInt(this, valueOffset, delta) + delta;
}
这里实际上都是调用getAndAddInt方法,Unsafe类有单独篇讲,这里只说一个方法
public final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
do {
var5 = this.getIntVolatile(var1, var2);
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
return var5;
}
先获取value值,然后把var5修改为var5+var4,修改失败再重新尝试修改,直到修改成功,返回的时候返回的var5,实际上是修改之前的值。
AtomicInteger 函数式接口参数方法
//将旧值传给updateFunction得到新值,然后比较更新,如失败则重复循环,直至成功返回旧值
public final int getAndUpdate(IntUnaryOperator updateFunction) {
int prev, next;
do {
prev = get();
next = updateFunction.applyAsInt(prev);
} while (!compareAndSet(prev, next));
return prev;
}
//将旧值传给updateFunction得到新值,然后比较更新,如失败则重复循环,直至成功返回新值
public final int updateAndGet(IntUnaryOperator updateFunction) {
int prev, next;
do {
prev = get();
next = updateFunction.applyAsInt(prev);
} while (!compareAndSet(prev, next));
return next;
}
//将旧值和x传给accumulatorFunction得到新值,然后比较更新,如失败则重复循环,直至成功返回旧值
public final int getAndAccumulate(int x,
IntBinaryOperator accumulatorFunction) {
int prev, next;
do {
prev = get();
next = accumulatorFunction.applyAsInt(prev, x);
} while (!compareAndSet(prev, next));
return prev;
}
//将旧值和x传给accumulatorFunction得到新值,然后比较更新,如失败则重复循环,直至成功返回新值
public final int accumulateAndGet(int x,
IntBinaryOperator accumulatorFunction) {
int prev, next;
do {
prev = get();
next = accumulatorFunction.applyAsInt(prev, x);
} while (!compareAndSet(prev, next));
return next;
}
转载:https://blog.csdn.net/nan8426/article/details/106166700