聊聊 CAS

哥有故事,你有酒,长夜漫漫,听我给你说。编程

 参考资源:api

https://blog.csdn.net/hsuxu/article/details/9467651安全

 

1.概述并发

CAS,compare and swap ,“比较交换”的意思。它是一种并发状态下的,比较交换的策略。性能

想必,咱们必定据说过乐观锁的概念,并发中乐观锁的核心概念就是应用了CAS。它包含了三个值:内存值,预期值和更新值。当内存值和预期值相等时,就会使用更新值将原来的数据(预期值)进行更新;若是不相等,则什么都不作。atom

 

2.例子spa

举个经典的例子,帮助你们理解。(伪代码).net

 1  public class AtomicInt {
 2    private volatile int value;
 3    public final int get() {
 4        return value;
 5     }
 6 
 7 publicfinal int getAndIncrement() {
// 下面的for的无限循环,就是经典的CAS自旋(Compare and swap)
8 for (;;) { 9 int current = get(); 10 int next = current + 1; 11 if (compareAndSet(current, next)) 12 return current; 13 } 14 } 15 16 public final boolean compareAndSet(int expect, int update) { 17 unsafe.compareAndSwapInt方法(方法内部,使用JNI调用C的代码); 18 } 19 }

 

3.凡事问个为何.线程

为何要比较?为何要用CAS的自旋?直接设值不行吗?它有什么优势缺点?code

例如,i++ 这个简单的操做不是一步完成的,而是分了三步。第一步,取值,第二步加一,第三部更新值。

假设有A,B两个线程同时操做i++这个处理,那么,当线程A完成上述第二步的时候,线程B已经将I的值更新(第三步)作完了。这样就会致使值发生异常,就是所谓的线程不安全。

因此,利用了乐观锁的思想采用了自旋的方式,每一次,就会先取得加一后的值,再将旧的值和内存中的值进行比较,若是相等,则说明,没有被别的线程动过,所以能够正常更新;若是不相等,则说明值已经被更新了,放弃本次的操做,从头再来,再从新取值,加一,更新。

 

CAS自旋(乐观锁)避免了悲观锁独占的现象,同时提升了并发的性能。可是,它也是有缺点的。(第三点参考了其余文章)

①乐观锁只能保证一个变量的的原子操做,多个变量的话,就没有办法了。

②长时间自旋,致使CPU消耗过大。

③ABA问题。CAS的核心思想是经过比对内存值与预期值是否同样而判断内存值是否被改过,可是,假如内存值原来是A,后来被一条线程改成B,最后又被改为了A,则CAS认为此内存值并无发生改变,但实际上,被其余线程改过。这种状况对依赖过程值的情景的运算结果影响很大。解决的思路是引入版本号,每次变量更新都把版本号加一。

 

4. 原子类Atomic

如今习惯多去查api文档(这是个好的习惯)。在JUC的atomic包下有以下几个类:

AtomicBoolean
AtomicInteger
AtomicLong
AtomicMarkableReference
AtomicReference

它们的原理都是应用了CAS的自旋,这几个类在并发编程中常常用到,它们都是线程安全的类。

 

就聊这么多,祝君美梦!

相关文章
相关标签/搜索