CAS(Compare And Swap)是一种硬件级别的原子操作,通过比较当前值(Var)跟旧值也可以叫做预期值(Expect)是否相等,假如相等,那么就将当前值修改为新值(New);反之则代表对应的资源被其他线程修改过,则放弃此次修改。但是这里的“放弃”并不是直接挂起,而是答应其再次进行尝试,尝试的过程依旧会占用CPU资源,自然,尝试也有肯定的次数限定。这其实就是自旋,即:
自旋是一种线程在竞争共享资源时不立刻阻塞,而是通过循环(忙等待)反复尝试获取锁或实验操作 的机制。其核心目的是 制止线程挂起和叫醒的开销(如上下文切换、内核态切换),适用于 短时间等待 的场景。
a. CAS三要素
b. 长时间自旋问题:
起首必须理清晰一个概念,为什么CAS看起来如许好,但是却只推荐在并发量比较小的时间使用?雷同于sychnoized当中的轻量级锁,在高并发的场景下其依旧无法替换像mutex如许的基于互斥锁实现的功能?一个方面就是因为CAS的操作其实大部门都是自旋的,高并发情况下,可能有的线程它需要一段时间才能获取到对应的资源,那么在这一段时间内,其并没有阻塞,而是一直在运行,吃CPU资源,线程比较少还好,一旦躲起来,CPU负担可想而知。
也就是说,线程在自旋失败之后,还是在不简短的发起读请求,从而对CPU造成了比较大的资源浪费。针对于此,办理思绪是让JVM支持硬件级处理器提供的pause指令。
pause指令能够让自旋失败的线程,先睡眠一段时间,之后再继续自旋。需要注意的一点是,在pause的这段时间里,此线程还是占有CPU的,不是像线程阻塞一样,直接放弃。睡眠的这一段时间,能够使得读操作的频率降低很多,提高效率。
c. 单变量限定
CAS对于单个变量能够保持原子性,但是共享变量一旦酿成多个,那么就无法包管了,此时办理方法有两个