CAS
public final int getAndAddInt(Object var1, long var2, int var4) { int var5; do {
//获取数据 var5 = this.getIntVolatile(var1, var2);
//比较数据 v1和v2找到值 和v5做比较 } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4)); return var5; }
v1是当前对象,v2是内存地址偏移量,通过v1和v2可以查找到一个精确的数据并拷贝到自己线程工作区域内,然后根据这个数据和v5进行比较,只要是一致的,那么执行v5 + v4
当线程被切换过之后,那么此时,v5还是v5,但是v1和v2的值却不一定等于v5了,因为已经切换过其他线程,其他线程可能对这个v1和v2已经做了修改,如果做了修改,那么将继续循环比较,如此往复,直到成功
2:直接操作主内存 不存在数据不一致问题
3:通过自旋锁方式,对数据进行比较和交换
缺点:
1:自旋锁对cpu开销特别大
2:只能保证一个共享变量的原子操作
3:导致ABA问题
ABA问题:
两个线程通过cas操作同一个变量,当T1线程和T2线程都获得主内存X的时候,T1的期望值是A想要修改成B,但是T2线程快速的将主内存A修改为任意值,然后又将任意值修改回A,此时T1再次获取主内存 值的时候发现 还是A就做了修改。表面上程序是正常运行的,但是这个过程中这个值是存在多变的,不保证这个过程没有问题!
代码示例:
import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; public class test { static AtomicReference<Integer> atomicReference = new AtomicReference<>(100); public static void main(String[] args) { new Thread(() -> { atomicReference.compareAndSet(100,101); atomicReference.compareAndSet(101,100); },"t1").start(); new Thread(() -> { try { TimeUnit.SECONDS.sleep(2); //在本次修改之前 其实数据已经被修改过,但是此处只做第一次和最后一次的比较,发现100=100,所以就直接继续修改完成 System.out.println(atomicReference.compareAndSet(100, 2000) + " \t getVaue:" + atomicReference.get()); }catch (Exception d){ d.printStackTrace(); } },"t2").start(); } }
解决ABA问题:
通过 AtomicStampedReference来添加版号作为修改的依据,如下代码,只要ABA发生,数据则修改失败!
import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicStampedReference; public class test { static AtomicReference<Integer> atomicReference = new AtomicReference<>(100); static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(100,1); public static void main(String[] args) { new Thread(() -> { atomicReference.compareAndSet(100,101); atomicReference.compareAndSet(101,100); },"t1").start(); new Thread(() -> { try { TimeUnit.SECONDS.sleep(2); System.out.println(atomicReference.compareAndSet(100, 2000) + " \t getVaue:" + atomicReference.get()); }catch (Exception d){ d.printStackTrace(); } },"t2").start(); //处理ABA问题 new Thread(() -> { try { TimeUnit.SECONDS.sleep(3); }catch (Exception e){ e.printStackTrace(); } atomicStampedReference.compareAndSet(100,200,atomicStampedReference.getStamp(),atomicStampedReference.getStamp()+1); atomicStampedReference.compareAndSet(200,100,atomicStampedReference.getStamp(),atomicStampedReference.getStamp()+1); },"t3").start(); new Thread(() -> { int stamp = atomicStampedReference.getStamp(); try { TimeUnit.SECONDS.sleep(3); }catch (Exception e){ e.printStackTrace(); } boolean b = atomicStampedReference.compareAndSet(100, 500, stamp, stamp + 1); System.out.println(Thread.currentThread().getName() + " \t 版本号:" + stamp + ",当前版本号: "+atomicStampedReference.getStamp()+"修改结果:" + b + ",实际值是:" + atomicStampedReference.getReference()); },"t4").start(); } }