AtomicInteger
public static void main(String[] args) { AtomicInteger ai = new AtomicInteger(20); System.out.println(ai.incrementAndGet()); }
在学习AtominInteger时,第一次接触了CAS,也就是在自增的时候使用CAS自旋锁解决并发问题。调用的方法时incrementAndGet方法。而这个自增的操作本质上不是一个原子性操作,但是改方法在没有加synchronized的情况下实现了线程安全。下面深入学习CAS:
/**
* Atomically increments by one the current value.
* 以原子性的方法,将当前值+1
* @return the updated value
*/
public final int incrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
这里用到了unsafe变量,该变量比较重要,以后解答,先看getAndAddInt方法
//操作源码,传入三个值,V,A,B,第一个V是AtomicInteger维护的变量value,表示当前数的实际值,他被volatile修饰来保证其可见性。第二个值A为当前希望操作的值,B为当前希望修改后的值。
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;
}
整个CAS被三个值主导:V,A,B。首先CAS,compareAndSet方法将A与实际值V进行比对,如果相等,那么就可以操作修改为B,如果不等那就放弃操作。
这样保证了修改的一致性,但是不能保证修改的原子性,因为他有两个操作,一个是比对,第二个是修改。假设现在线程1需要将value = 1修改为2,那么比对A=1和V=1,发现相同那么修改。此时线程2比对A=1和V=1,发现也相同,把V修改为3。线程2执行完毕,而在线程1中,此时的V已经是3了,但是线程1已经经历过了比对操作,将3又修改为了2,这样就造成了严重的原子性问题。
这里是基于HotSpot底层调用操作系统来完成原子性操作的,在操作系统执行比对并修改的CAS操作时,加上了底层锁,保证了操作原子性,而我们使用Java的时候全然不知。