Java多线程并发中 CAS 的使用与理解

一、CAS (Compare And Swap):

  CAS(Compare And Swap),即比较并交换 CAS(V,E,N)。是解决多线程并行情况下使用锁造成性能损耗的一种机制,CAS操作包含三个操作数——要更新的变量(V)、预期原值(E)和新值(N)。核心算法是如果V 值等于E 值,则将V 的值设为N 。若V 值和E 值不同,则说明已经有其他线程做了更新,则当前线程不做更新,直到V、E两个值相等,才更新V的值。
  1、代码演示:

1/* 2* 原子变量类: 3* AtomicBoolean 4* AtomicInteger 5* AtomicLong 6* AtomicReference 7* 8* 原子数组类: 9* AtomicLongArray 10* AtomicReferenceArray 11* 12* 原子方式更新对象中的字段类: 13* AtomicIntegerFieldUpdate 14* AtomicReferenceFieldUpdate 15* 16* 高并发汇总类: 17* LongAdder 18* LongAccumulator 19* DoubleAdder 20* DoubleAccumulator 21* 22*/ 23public class CASTest { 24 25 public static void main(String[] args) throws InterruptedException { 26 AtomicInteger counter = new AtomicInteger(0); 27 CountDownLatch c = new CountDownLatch(10000); 28 29 for(int i = 0; i < 50; i++){ 30 new Thread(new Runnable() { 31 @Override 32 public void run() { 33 System.out.print( counter.incrementAndGet() + " "); 34 c.countDown(); 35 } 36 }).start(); 37 } 38 c.await(); 39 System.out.println("AtomicInteger :" + counter.get()); 40 } 41}

二、CAS 中 ABA 问题:

  ABA 问题是指假设当前值为 A ,如果另一个线程先将 A 修改成 B , 再修改回成 A ,当前线程的 CAS 操作无法分辨当前值发生过变化。ABA 是不是一个问题与程序的逻辑有关,一般不是问题。而如果确实有问题,解决方法是使用 AtomicStampedReference ,在修改值的同时附加一个时间戳,只有值和时间戳都相同才进行修改。

  1、代码演示:

1public class ABATest { 2 public static void main(String[] args) throws InterruptedException { 3 CASABATest(); 4 atomicStampedReferenceTest(); 5 } 6 7 public static void atomicStampedReferenceTest(){ 8 AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(0, 0); // 第一个参数:引用对象的初始值,第二个参数:这个对象的初始标记 9 10 new Thread(new Runnable() { 11 @Override 12 public void run() {         // compareAndSet(eR,nR,eS,nS) eR:引用对象的期望值,nR:引用对象的新值,eS:引用对象期望标记,nS:引用对象的新标记,当 eR、eS和当前线程的值相等才会修改eR、eS的值为nR、nS 13 System.out.println(Thread.currentThread().getName() + ", " + atomicStampedReference.compareAndSet(0, 1, 0, 1) + ", atomicStampedReference value:" + atomicStampedReference.getReference()); 14 } 15 },"Thread A").start(); 16 17 18 new Thread(new Runnable() { 19 @Override 20 public void run() { 21 System.out.println(Thread.currentThread().getName() + ", " + atomicStampedReference.compareAndSet(1, 0, 1, 2) + ", atomicStampedReference value:" + atomicStampedReference.getReference()); 22 } 23 },"Thread B").start(); 24 25 26 new Thread(new Runnable() { 27 @Override 28 public void run() { 29 System.out.println(Thread.currentThread().getName() + ", " + atomicStampedReference.compareAndSet(0, 1, 0, 1) + ", atomicStampedReference value:" + atomicStampedReference.getReference()); 30 } 31 },"Thread C").start(); 32 33 } 34 35 /** 36 * 演示CAS 更新的ABA 问题 37 * 38 */ 39 public static void CASABATest() throws InterruptedException { 40 AtomicInteger integer = new AtomicInteger(0); 41 42 new Thread(new Runnable() { 43 @Override 44 public void run() {          //compareAndSet(e,u) e:期望值,u:新值,如果e的值在当前线程中和integer的值一致,就把e的值修改成u的值 45 System.out.println(Thread.currentThread().getName() + ", " + integer.compareAndSet(0, 1) + ", AtomicInteger value:" + integer); //true 46 } 47 },"Thread A").start(); 48 49 50 new Thread(new Runnable() { 51 @Override 52 public void run() { 53 System.out.println(Thread.currentThread().getName() + ", " + integer.compareAndSet(1 , 0) + ", AtomicInteger value:" + integer); //true 54 } 55 },"Thread B").start(); 56 57 58 new Thread(new Runnable() { 59 @Override 60 public void run() { 61 System.out.println(Thread.currentThread().getName() + ", " + integer.compareAndSet(0 , 1) + ", AtomicInteger value:" + integer); //true 62 } 63 },"Thread C").start(); 64 65 } 66}

三、CAS 与 Synchronized 的对比:
  1.synchronized 是悲观的,它假设更新都是可能冲突的,所以要先获取锁,得到锁才更新,它是阻塞式算法,得不到锁就进入锁池等待。
  CAS 是乐观的,它假设冲突比较少,但使用CAS 更新,进行冲突检测,如果确实冲突就继续尝试直到成功,它是非阻塞式算法,有更新冲突就重试。

点赞
收藏

评论区

加载中...

相关推荐

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

java CAS compareAndSet, compareAndSwap 区别

之前看源代码的时候,发现了有两个方法。一个是compareAndSet,一个是compareAndSwap,傻傻分不清这两个到底哪个是CAS呢。我看了java并发编程实战找到了答案。CAS是一种计算机的指令。CAS包含3个操作数,需要读写的内存位置V,进行比较的值A和拟写入的新值B。当且仅当V的值等于A时,C

java多线程之CAS

CAS(CompareandSwap)CAS字面意思为比较并交换.CAS有3个操作数,分别是:内存值M,期望值E,更新值U。当且仅当内存值M和期望值E相等时,将内存值M修改为U,否则什么都不做。1.CAS的应用场景CAS只适用于线程冲突较少的情况。CAS的典型应用场景是:

Java多线程并发06——CAS与AQS

在进行更近一步的了解Java锁的知识之前,我们需要先了解与锁有关的两个概念CAS与AQS。关注我的公众号「Java面典」了解更多Java相关知识点。CAS(CompareAndSwap/Set)概念CAS函数,是比较并交换函数,它是原子操作函数。原理CA

KVM调整cpu和内存

一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid

Java并发机制底层实现原理

锁的膨胀过程预备知识CAS硬件对并发的支持在大多数处理器架构(包括IA32和Sparc)中采用的方法是实现一个比较并交换(CAS)指令,CAS包含了3个操作数——内存位置(V),预期原值(A),拟写入的新值(B),当且仅当VA时,CAS才会通过原子方式用新值(B)来更新(V)原有的值,无论操作成