网站后台seo优化如何做,2022成都解封倒计时,腾讯风铃怎么做网站,五个网站页面这次分享一些关于原子操作(CAS)的东西.
定义
CAS(Compare And Swap)是CPU的一个指令级别的操作#xff0c;叫原子操作#xff0c;原子操作是不可分割的#xff0c;跟事务差不多#xff0c;要么全部执行完成#xff0c;要么不执行#xff1b;
像这种操作有点类似阻塞锁…这次分享一些关于原子操作(CAS)的东西.
定义
CAS(Compare And Swap)是CPU的一个指令级别的操作叫原子操作原子操作是不可分割的跟事务差不多要么全部执行完成要么不执行
像这种操作有点类似阻塞锁机制但是使用阻塞锁机制去控制的话会比较消耗性能而使用CAS操作的话会比使用锁更快。
与synchronized性能比较最简单的一个测试Demo
public class AtomicNumber {AtomicInteger ai new AtomicInteger(0);int i 0;public synchronized void addInteger() {i ;}public void addAtomicInteger() {ai.getAndIncrement();}public static void main(String[] args) throws InterruptedException {long time System.currentTimeMillis();final AtomicNumber atomicNumber new AtomicNumber();final CountDownLatch latch new CountDownLatch(2);int count 0;while(count2) {new Thread(new Runnable() {public void run() {for(int j0;j200000;j)atomicNumber.addAtomicInteger();latch.countDown();}}).start();count;}latch.await();System.out.println(花费的时间(System.currentTimeMillis()-time) ms);System.out.println(atomicInteger value:atomicNumber.ai.get());final CountDownLatch latch1 new CountDownLatch(2);count 0;time System.currentTimeMillis();while(count2) {new Thread(new Runnable() {public void run() {for(int j0;j200000;j)atomicNumber.addInteger();latch1.countDown();}}).start();count;}latch1.await();System.out.println(花费的时间(System.currentTimeMillis()-time) ms);System.out.println(i value:atomicNumber.i);}
}//运行的结果
花费的时间14ms
atomicInteger value:400000
花费的时间35ms
i value:400000
//很明显使用原子操作会比使用锁机制要快。
CAS里面有三个操作数1、内存地址(V)2、期望的值(A)3、新值(B)
主要思想如果内存地址V的期望值等于A时则将地址V赋值给新值B如果不相等算CAS操作失败则不做任何操作但触发了CAS操作如果内存地址上的值V不等于A的话就会进入死循环一直做CAS操作一直到相等也就是成功这个循环过程叫自旋。
存在的问题
1、ABA问题即当取出内存地址V的时候期望值从A变成新值B然后有从B变成A值然后再将V与期望值相比发现一值其实这个过程确实发生了变化只是结果值与初始值一致
像这样的问题我们可以采用两个方式第一种就是在期望值变化的时候加上一个版本号(AtomicStampedReference)从A1变成B2变成A3这样就能解决这样的问题了另外一种就是变化了就标记期望值已变化(AtomicMarkableReference)。
2、开销比较大长期处于自旋的CAS操作会导致性能消耗。
3、只能保证只有一个共享变量进行原子操作在Java中有个专门处理的类来解决这个问题(AtomicReference)
JDK提供的原子操作类
AtomicInteger
用法在上面的那个案例有了就不多说了有几个需要注意的地方
1、在使用自增的方法有两个1、getAndIncrement() 这个是先获取值在自增。2、incrementAndGet() 先自增然后在获取值。这两个方法的差别有点类似 i 以及 i的操作。
AtomicReference
这个是原子操作引用类型结果来看原子引用并不会改变原始的值。 static AtomicReferenceUserInfo reference new AtomicReferenceUserInfo();public static void main(String[] args) {UserInfo userInfo1 new UserInfo(Mark,12);reference.set(userInfo1);UserInfo userInfo2 new UserInfo(Mark12,23);reference.compareAndSet(userInfo1, userInfo2);System.out.println(new data:);System.out.println(reference.get().getName());System.out.println(reference.get().getAge());System.out.println(old reference object:);System.out.println(userInfo1.getName());System.out.println(userInfo1.getAge());}static class UserInfo {String name;Integer age;public UserInfo(String name, Integer age) {super();this.name name;this.age age;}public String getName() {return name;}public void setName(String name) {this.name name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age age;}}//运行结果
new data:
Mark12
23
old reference object:
Mark
12AtomicStampedReference
在期望值变化的时候加上一个版本号在做CAS操作的时候如果不一致会返回为false并且不会做任何操作 /*** p需要一个初始值以及初始版本号*/static AtomicStampedReferenceString reference new AtomicStampedReferenceString(Java,0);public static void main(String[] args) throws InterruptedException {final String value reference.getReference();final int stamp reference.getStamp();System.out.println(value: value version:stamp);Thread correctThread new Thread(new Runnable() {public void run() {System.out.println(Thread.currentThread().getName() old reference:value version:stamp CAS STATUS : reference.compareAndSet(value, value is the beast Language, stamp, 1));System.out.println(Thread.currentThread().getName() value: reference.getReference() version:reference.getStamp());}});Thread errorThread new Thread(new Runnable() {public void run() {System.out.println(Thread.currentThread().getName() old reference:reference.getReference() version:reference.getStamp() CAS STATUS : reference.compareAndSet(value, value Hello World!!, stamp, 2));System.out.println(Thread.currentThread().getName() value: reference.getReference() version:reference.getStamp());}});correctThread.start();correctThread.join();errorThread.start();errorThread.join();System.out.println(value: reference.getReference() version:reference.getStamp());}//运行结果
value:Java version:0
value:Java version:0
Thread-0 old reference:Java version:0 CAS STATUS : true
Thread-1 old reference:Java version:0 CAS STATUS : false
Thread-0value:Java is the beast Language version:1
Thread-1value:Java is the beast Language version:1
目前就这么多啦至于AtomicMarkableReference这个原子引用大家了自己去试一下跟AtomicStampedReference差不多好啦该洗洗睡了。