源码说话,咱们看一下getAndIncrement方法:java
1 //该方法功能是Interger类型加1 2 public final int getAndIncrement() { 3 //主要看这个getAndAddInt方法 4 return unsafe.getAndAddInt(this, valueOffset, 1); 5 } 6 7 //var1 是this指针 8 //var2 是地址偏移量 9 //var4 是自增的数值,是自增1仍是自增N 10 public final int getAndAddInt(Object var1, long var2, int var4) { 11 int var5; 12 do { 13 //获取内存值,这是内存值已是旧的,假设咱们称做指望值E 14 var5 = this.getIntVolatile(var1, var2); 15 //compareAndSwapInt方法是重点, 16 //var5是指望值,var5 + var4是要更新的值 17 //这个操做就是调用CAS的JNI,每一个线程将本身内存里的内存值M 18 //与var5指望值E做比较,若是相同将内存值M更新为var5 + var4,不然作自旋操做 19 } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4)); 20 21 return var5; 22 }
解释一下getAndAddInt方法的流程:
假设有一下情景:多线程
简单来讲,就是将工做内存的值与主内存的值来进行比较,若是相等,说明没有被其余线程修改,则进行赋新值操做,若是不相等,说明主内存的数据被其余线程更改过,则此时须要更新工做内存的副本值,而且从新获取主内存的值,再次进行比较,直到两者相等为止;jvm
非阻塞的轻量级的乐观锁,经过CPU指令实现,在资源竞争不激烈的状况下性能高,相比synchronized重量锁,synchronized会进行比较复杂的加锁、解锁和唤醒操做。性能
- ABA问题: 线程C、D;线程D将A修改成B后又修改成A,此时C线程觉得A没有改变过,java的原子类AtomicStampedReference,经过控制变量值的版本号来保证CAS的正确性。具体解决思路就是在变量前追加上版本号,每次变量更新的时候把版本号加一,那么A - B - A就会变成1A - 2B - 3A。
- 自旋时间过长,消耗CPU资源,若是资源竞争激烈,多线程自旋长时间消耗资源