什么是CAS
CAS底层是使用了unsafe类
要注意,其中用学过的volatile修饰了value,使修改了value以后其他线程可见,其他线程就可以compare and swap
代码展示CAS
/*
* CAS:Compare and swap [比较并交换]
* */
public class AtomicIntegerDemo {
public static void main(String[] args) {
AtomicInteger atomicInteger=new AtomicInteger(5);
//true 2019
System.out.println(atomicInteger.compareAndSet(5, 2019)+"\t"+atomicInteger.get());
//false 2019
System.out.println(atomicInteger.compareAndSet(5, 2222)+"\t"+atomicInteger.get());
}
}
上图的代码是new了一个AtomicIntrger,这只针对了整数,那是否也可以对对象进行CAS呢,答案是可以的,我们可以使用AtomicReference,详情见如下代码
CAS通过AtomicReference实现自旋锁
CAS的两大缺点
- ①. 循环时间长开销很大
- 如果一直失败就会一直尝试
- ②.容易造成ABA问题
- ABA问题:改了一次,又改回来,会让计算机以为没有改 注意:AtomicStampedReference用来解决AtomicInteger中的ABA问题,该demo企图将integer的值从0一直增长到1000,但当integer的值增长到128后,将停止增长。出现该现象有两点原因:
-
使用int类型而非Integer保存当前值
Interger对-128~127的缓存[这个范围才有效,不在这个范围comareAndSet会一直返回false
————————————————
版权声明:本文为CSDN博主「所得皆惊喜」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/TZ845195485/article/details/117712307 -
/** * Description: ABA问题的解决 * * @author veliger@163.com * @date 2019-04-12 21:30 **/ public class ABADemo { private static AtomicReference<Integer> atomicReference=new AtomicReference<>(100); private static AtomicStampedReference<Integer> stampedReference=new AtomicStampedReference<>(100,1); public static void main(String[] args) { System.out.println("===以下是ABA问题的产生==="); new Thread(()->{ atomicReference.compareAndSet(100,101); atomicReference.compareAndSet(101,100); },"t1").start(); new Thread(()->{ //先暂停1秒 保证完成ABA try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(atomicReference.compareAndSet(100, 2019)+"\t"+atomicReference.get()); },"t2").start(); try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("===以下是ABA问题的解决==="); new Thread(()->{ int stamp = stampedReference.getStamp(); System.out.println(Thread.currentThread().getName()+"\t 第1次版本号"+stamp+"\t值是"+stampedReference.getReference()); //暂停1秒钟t3线程 try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } stampedReference.compareAndSet(100,101,stampedReference.getStamp(),stampedReference.getStamp()+1); System.out.println(Thread.currentThread().getName()+"\t 第2次版本号"+stampedReference.getStamp()+"\t值是"+stampedReference.getReference()); stampedReference.compareAndSet(101,100,stampedReference.getStamp(),stampedReference.getStamp()+1); System.out.println(Thread.currentThread().getName()+"\t 第3次版本号"+stampedReference.getStamp()+"\t值是"+stampedReference.getReference()); },"t3").start(); new Thread(()->{ int stamp = stampedReference.getStamp(); System.out.println(Thread.currentThread().getName()+"\t 第1次版本号"+stamp+"\t值是"+stampedReference.getReference()); //保证线程3完成1次ABA try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } boolean result = stampedReference.compareAndSet(100, 2019, stamp, stamp + 1); System.out.println(Thread.currentThread().getName()+"\t 修改成功否"+result+"\t最新版本号"+stampedReference.getStamp()); System.out.println("最新的值\t"+stampedReference.getReference()); },"t4").start(); }