IT评测·应用市场-qidao123.com技术社区

标题: CAS(Compare And Swap) [打印本页]

作者: 天津储鑫盛钢材现货供应商    时间: 6 天前
标题: CAS(Compare And Swap)
1. 乐观锁 - 灰心锁

灰心锁:以大家比较了解的sychronized为例子,其就是一个比较典型的灰心锁,灰心锁因为比较灰心,它以为在任何情况下都会天有不测风云,也就是说线程每次访问共享资源的时间都会出现辩论,所以必须先对数据进行上锁,从而包管对应的临界区资源在同一个时间段只能有一个资源去访问。
乐观锁:乐天派,它以为每次访问都不会出现对共享资源访问的辩论,所以在对共享资源访问的时间不会上锁,即多个线程均无需加锁,也无需等待。假如出现对共享资源访问的辩论,那么就会使用CAS的技能以确保线程实验的安全性。
从乐观锁的角度来看,其是肯定不会出现死锁的现象的,因为其不上锁,所有线程都不会阻塞等待,永远的乐天派;灰心锁就相反了,逻辑处理不好就很容易出现死锁的现象。
灰心锁:多用于“写多读少”,以制止共享资源修改辩论
乐观锁:多用于“读多写少”,以提高效率。
以此引入CAS的技能,下面让我们来解开CAS机密的面纱。

2. 什么是CAS?

        2.1 简要概念

        CAS(Compare And Swap)是一种硬件级别的原子操作,通过比较当前值(Var)跟旧值也可以叫做预期值(Expect)是否相等,假如相等,那么就将当前值修改为新值(New);反之则代表对应的资源被其他线程修改过,则放弃此次修改。但是这里的“放弃”并不是直接挂起,而是答应其再次进行尝试,尝试的过程依旧会占用CPU资源,自然,尝试也有肯定的次数限定。这其实就是自旋,即:
        自旋是一种线程在竞争共享资源时不立刻阻塞,而是通过循环(忙等待)反复尝试获取锁或实验操作 的机制。其核心目的是 制止线程挂起和叫醒的开销(如上下文切换、内核态切换),适用于 短时间等待 的场景。
        a. CAS三要素

在上面已经大致说过了其运行的根本原理,就是通过比较当前值跟旧值是否相等,相等代表未被修改,将当前值V变为新值N,不等则不做修改,不断尝试,再次比较。
举一个例子:
        现在在多线程的状态下,多个线程同时想要修改一个变量 S(代指Var) ,其本来的值为 S = 5(代指Expect),需要对其进行+1的操作,酿成新值 6(代指New),其实验的流程如下:
        起首,线程会比较当前值 S 跟旧值 5 是否一样,确保没有被修改,假如一样,将其更换为新值 6,这个时间 S的值就酿成了6
        假如发现S != 5 那么当前线程就会放弃本次修改操作,之后再尝试数次,次数用尽后主动放弃修改。
        那么会不会出现说,我现在的S = 5,也就是跟旧值是一样的,但是预备修改的时间出现其他的线程将其修改为新值6了呢?不消担心,这种情况不会发生,因为CAS在底层是具有原子性的,要么同时乐成,要么不乐成。它是一种系统原语,是一条CPU指令,所以说底层是具有原子性的。

        2,2  CAS优缺点

        优点:


        缺点:

        2.3 CAS所面对的三个问题

        a.ABA问题:
        办理ABA问题,比较常见的方法就是使用版本号或者是时间戳用以进行记录,每次修改不光修改对应的值,而且记录当下的时间戳,如许就包管了每次的原子性修改肯定是跟之前的不一样的,从而办理ABA问题。
而在AtomicStampedReference当中,就设置了一个Pair内部类,用于记录时间戳,同时还使用native作了一个标记,使得这个静态变量具有可见性,如图:


        b. 长时间自旋问题:
        起首必须理清晰一个概念,为什么CAS看起来如许好,但是却只推荐在并发量比较小的时间使用?雷同于sychnoized当中的轻量级锁,在高并发的场景下其依旧无法替换像mutex如许的基于互斥锁实现的功能?一个方面就是因为CAS的操作其实大部门都是自旋的,高并发情况下,可能有的线程它需要一段时间才能获取到对应的资源,那么在这一段时间内,其并没有阻塞,而是一直在运行,吃CPU资源,线程比较少还好,一旦躲起来,CPU负担可想而知。
        也就是说,线程在自旋失败之后,还是在不简短的发起读请求,从而对CPU造成了比较大的资源浪费。针对于此,办理思绪是让JVM支持硬件级处理器提供的pause指令。
        pause指令能够让自旋失败的线程,先睡眠一段时间,之后再继续自旋。需要注意的一点是,在pause的这段时间里,此线程还是占有CPU的,不是像线程阻塞一样,直接放弃。睡眠的这一段时间,能够使得读操作的频率降低很多,提高效率。
        c. 单变量限定
        CAS对于单个变量能够保持原子性,但是共享变量一旦酿成多个,那么就无法包管了,此时办理方法有两个

3. CAS在JAVA中的实现

        在JAVA当中,CAS操作是由一个内部类Unsafe实现的,但是这个类是内部的,所以并不推荐直接使用。更具体的是通过JNI(Java Native Interface)实现的,如图所示:

        通过这些操作实现CAS,确保其原子性。
        在Java当中,可以使用并发包Atomic这些类,他们封装了CAS操作,提供了线程安全的原子操作。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 IT评测·应用市场-qidao123.com技术社区 (https://dis.qidao123.com/) Powered by Discuz! X3.4