0%

CAS基本原理

前言

实现原子操作可以使用锁(synchronized)和CAS,synchronized锁基于阻塞的重量级锁的机制,CAS是一种不会阻塞线程,更有效,更加灵活的机制。

目录

一、原子操作

在编程中,atomic (原子) 动作是一次性完全发生的动作(一个或多个操作)。原子动作不能在中间停止:它要么完全发生,要么根本不发生。

二、CAS原理

实现原子操作还可以现代处理器都支持CAS(Compare And Swap)指令,循环这个指令直到成功为止。

每一个CAS操作过程都包含三个运算符:一个内存地址V,一个期望的值A和一个新值B,操作的时候如果这个地址上存放的值等于这个期望的值A,则将地址上的值赋为新值B,否则不做任何操作。CAS(比较并且交换)是一种原子指令。

与synchronized的区别:

CAS是一种乐观锁,不会阻塞线程。

synchronized是一种悲观锁,是基于阻塞的锁机制,也就是说当一个线程拥有锁的时候,访问同一资源的其它线程需要等待,直到该线程释放锁。如果有大量的线程来竞争资源,那CPU将会花费大量的时间和资源来处理这些竞争,上下文切换耗费时间和性能。

三、CAS问题

  1. ABA问题:因为CAS需要在操作值的时候,检查值有没有发生变化,如果没有发生变化则更新,但是如果一个值原来是A,变成了B,又变成了A,那么使用CAS进行检查时会发现它的值没有发生变化,但是实际上却变化了。
  2. 循环时间长开销大:自旋CAS如果长时间不成功,会给CPU带来非常大的执行开销。
  3. 只能保证一个共享变量的原子操作;当对一个共享变量执行操作时,我们可以使用循环CAS的方式来保证原子操作,但是对多个共享变量操作时,循环CAS就无法保证操作的原子性,这个时候就可以用锁。

解决ABA问题:思路就是使用版本号。在变量前面追加上版本号,每次变量更新的时候把版本号加1。JDK提供AtomicStampedReference类和AtomicMarkableReference类。

解决只能保证一个共享变量问题:可以把多个共享变量合并成一个共享变量来操作。从Java 1.5开始,JDK提供了AtomicReference类来保证引用对象之间的原子性,就可以把多个变量放在一个对象里来进行CAS操作。

四、原子操作类

更新基本类型类:AtomicBoolean、AtomicInteger、AtomicLong

更新数组类:AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray

更新引用类型:AtomicReference、AtomicMarkableReference、AtomicStampedReference

AtomicStampedReference:利用版本戳的形式记录了每次改变以后的版本号,更新带有int类型标记位的引用类型,关心的是被修改过几次。

AtomicMarkableReference:更新带有boolean类型标记位的引用类型,关心的是有没有被修改过。

总结

Java并发编程:什么是CAS?这回总算知道了