Atomic 包中的类提供了对数据进行原子操作的功能。
例如
a++ 、a+=1等类似代码不是原子的,实现过程是由内存中取出数据,对数据进行计算,再结果写入内存,属于复合操作,由多条CPU指令完成。 在单线程下这些代码会运行良好,如果a是多线程中的共享变量,那么运行结果可能会不正确。
举列: a表示一个累计值,以a++为例:
X线程 从内存中取出a的值=5,执行a++,得出的结果是6,并未写回内存时前,Y线程从内存中取出a的值=5,X线程将a=6写回内存,但Y缓存中a的值=5,执行a++得出结果为6,写回内存a=6。 结果是两个线程分别对5进行加1操作,但结果等于6,累计值就少了1。
避免这种情况产生,可以采用如下方式:
1.采用 synchronized或 ReentrainLock锁 ,某一时刻只能有一条线程对a操作,即线程互斥。(阻塞方式)
2.采有原子类操作,将a定义为AtomicInteger或AtomicLong ,调用incrementAndGet方法加1. (非阻塞方式)
AtomicLong中的 incrementAndGet源码分析如下:
private volatile long value;//long数据值 标记为 volatile 每次读取写入值在主内存中操作,而不是线程的缓存中,使值的变化其它线程立即可见。
private static final Unsafe unsafe = Unsafe.getUnsafe(); //Unsafe 用于实现CAS(compare and swap) 操作,基于CPU一条原始指令,是原子的线程安全的,可用于多线程间非阻塞方式实现线程安全。
static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicLong.class.getDeclaredField("value"));//value值在内存中的偏移地址,用于直接修改内存值
} catch (Exception ex) { throw new Error(ex); }
}
public final long getAndIncrement() {
while (true) {//在循环中设定value的值,直至成功。
long current = get();//取出主内存中的value值存入线程栈
long next = current + 1;//线程栈中的value值+1
if (compareAndSet(current, next))//原子的设定value值,如果返回值是假,说明当前主内存中的实际值与线程栈中的值不相等,可能其它线程修改了内存中值,需要基于新值再次计算,即又一次循环
return current;
}
}
/**
*原子的操作方法,
* 如果expect(期望值)与value实际相等,说明数据没有被改过,就用update(新值)替换实际值并反回真,执行过程是原子的,线程安全,
* 如果expect(期望值)与value实际相等,说明数据可能被改过,返回假。
*
*/
public final boolean compareAndSet(long expect, long update) {
return unsafe.compareAndSwapLong(this, valueOffset, expect, update);
}
java.util.concurrent.atomic 原子更新的包 包含:AtomicBoolean --原子的更新boolean值 AtomicInteger --原子的更新integer值 AtomicLong --原子的更新long值 AtomicLongArray --原子的更新long数组 AtomicIntegerArray --原子的更新int数组 AtomicReference --原子的更新一个对象引用 AtomicReferenceFieldUpdater --原子的更新一个类实例中属性的引用 AtomicIntegerFieldUpdater --原子的更新一个类实例中int属性值 AtomicLongFieldUpdater --原子的更新一个类实例中long属性值 这些类基于unsafe类,使用cas方法和 volatile 来保证原子操作: 1,Unsafe类提供了硬件级别的原子操作,cas(compare and swap) 基于比较交换的方式(当前值相等的情况下,再设置新值),使用的方式 2. volatile 保证了内存的可见性。 /** * * 当前值+1,并返回当前值,原子的 * */ public final int getAndIncrement() { return unsafe.getAndAddInt(this, valueOffset, 1); } /** * 通过cas方式,不断循环设置新值,直到成功,返回旧值。 * */ 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; }