代码拉取完成,页面将自动刷新
CAS 全称是CompareAndSwap即__比较替换__的意思,是__原子操作__,采用__乐观锁__的概念,底层对应着CPU的__cmpxchg__指令,核心参数就是当前值A,要修改的值B,内存值V三个参数,在高并发的场景下不断循环比较当前值和内存值,一样就修改,否则就重试或者放弃更新。
与Syncronized和Lock相比而言,CAS是不需要在资源上加锁的,多个线程都可以直接去修改共享资源,但只能被一个线程修改。Syncronized和Lock都是只有一个线程去操作共享资源。在一定的场景下,CAS比较高效,比如一个数的累加,底层使用CAS的AutomaticInteger类就可以实现线程安全的自增。
ABA的问题:有三个线程,共享资源a为100,一号线程将a准备改为50,此时cpu被线程2抢占,修改为50,2号线程修改完后CPU被3号线程抢占,修改为100,修改后1号线程继续执行,此时1号线程不知道a已经有一次修改了,但依然能修改成功,a这就是ABA的问题。
版本号:a值每次被修改时版本号都会加1,此时线程1在比较时额外加上版本号的比较,就可以解决ABA的问题,可以使用A
版本号工具类:
- AtomicStampedReference:带时间版本戳的原子操作类,可以控制ABA问题,保证到修改几次。
import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicReference; /** * @ClassName ReferenceTest * @Description 多个变量需要同时Atomic控制时,封装到一个对象类中 AtomicReference解决。一个对象更新成另一个对象 **/ public class ReferenceTest { public static void main(String[] args) throws InterruptedException { MiddleStatus status=new MiddleStatus(10,5); AtomicReference<MiddleStatus> ato=new AtomicReference<>(status); MiddleStatus expect=new MiddleStatus(12,6); MiddleStatus newStatus=new MiddleStatus(20,10); //保证原子操作,更新之前会比较 expect ato.compareAndSet(expect,newStatus); System.out.println("status = " + ato.get()); //更新失败,MiddleStatus{esfCount=10, zfCount=5} ato.compareAndSet(status,newStatus); System.out.println("status = " + ato.get());//更新成功,MiddleStatus{esfCount=20, zfCount=10} } private static class MiddleStatus{ private int esfCount; private int zfCount; public MiddleStatus(int esf,int zf){ this.esfCount=esf; this.zfCount=zf; } @Override public String toString() { return "MiddleStatus{" + "esfCount=" + esfCount + ", zfCount=" + zfCount + '}'; } } }
- AtomicMarkableReference:可以控制ABA问题,保证是否修改过。
import java.util.concurrent.atomic.AtomicMarkableReference; import java.util.concurrent.atomic.AtomicStampedReference; /** * @ClassName StampTest * @Description 通过时间戳控制原子操作,保证是否有修改,并制定修改了多少次 **/ public class StampTest { private static class StampStatus{ public int sCount; public StampStatus(int c){ this.sCount=c; } } public static void main(String[] args) { StampStatus s1=new StampStatus(2); //通过Val和初始时间戳创建StampReference int initialStap=2; //AtomicStampedReference 可通过Stamp知道已经修改几次 AtomicStampedReference<StampStatus> ato=new AtomicStampedReference<>(s1,initialStap); ato.compareAndSet(new StampStatus(3),new StampStatus(6),3,ato.getStamp()+1); System.out.println(ato.getReference().sCount);//期望值和期望引用不正确,更新失败 //AtomicMarkableReference 可通过Mark知道是否更新过 AtomicMarkableReference<StampStatus> ato2=new AtomicMarkableReference<>(s1,false); ato2.compareAndSet(new StampStatus(3),new StampStatus(6),false,true); System.out.println(ato2.isMarked()); System.out.println(ato2.getReference().sCount);//期望标志和期望引用不对,修改失败 } }
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。