什么是乐观锁和悲观锁?CAS又是什么鬼?
悲观锁是将资源锁住,等一个之前获得锁的线程释放锁之后,下一个线程才可以访问。
乐观锁采取了一种宽泛的态度,通过某种方式不加锁来处理资源,可以使用版本号version和cas算法实现,性能较悲观锁有很大的提高。乐观锁适用于多读的应用类型,这样可以提高吞吐量
CAS算法
CAS全拼又叫做compareAndSwap,从名字上的意思就知道是比较交换的意思
它包含 3 个参数 CAS(V,E,N),V表示要更新变量的值,E表示预期值,N表示新值。仅当 V值等于E值时,才会将V的值设为N,如果V值和E值不同,则说明已经有其他线程做两个更新,则当前线程则什么都不做。最后,CAS 返回当前V的真实值。
它涉及到三个操作数:内存值、预期值、新值
cas是一种基于锁的操作,而且是乐观锁。在java中锁分为乐观锁和悲观锁。悲观锁是将资源锁住,等一个之前获得锁的线程释放锁之后,下一个线程才可以访问。而乐观锁采取了一种宽泛的态度,通过某种方式不加锁来处理资源,比如通过给记录加version来获取数据,性能较悲观锁有很大的提高。
CAS机制的优缺点
(1)优点
一开始在文中我们曾经提到过,cas是一种乐观锁,而且是一种非阻塞的轻量级的乐观锁,什么是非阻塞式的呢?其实就是一个线程想要获得锁,对方会给一个回应表示这个锁能不能获得。在资源竞争不激烈的情况下性能高,相比synchronized重量锁,synchronized会进行比较复杂的加锁,解锁和唤醒操作。
(2)缺点
缺点也是一个非常重要的知识点,因为涉及到了一个非常著名的问题,叫做ABA问题。假设一个变量 A ,修改为 B之后又修改为 A,CAS 的机制是无法察觉的,但实际上已经被修改过了。这就是ABA问题
乐观锁的缺点:
1、ABA问题
解决办法:
JDK 1.5 以后的 AtomicStampedReference 类就提供了此种能力,其中的compareAndSet 方法就是首先检查当前引用是否等于预期引用,并且当前标志是否等于预期标志,如果全部相等,则以原子方式将该引用和该标志的值设置为给定的更新值。
2、循环时间长导致cpu的开销大
自旋CAS如果一直没有获取锁或一直等待。
解决办法:
如果JVM支持处理器的PAUSE指令,两个作用:1、延长流水线执行指令(时间取决于实现的版本),使CPU不会消耗过多的资源;2、避免退出循环时因内存顺序冲突引起的CPU流水线被清空。
3、只能保证一个共享变量的原子操作
CAS 只对单个共享变量有效,当操作涉及跨多个共享变量时CAS 无效
解决办法:
JDK1.5后AtomicStampedReference类确保引用对象之间的原子性,可以把多个变量放在一个对象里来进行 CAS 操作.所以我们可以使用锁或者利用 AtomicReference 类把多个共享变量合并成一个共享变量来操作。
本文作者:好名字
原文链接:https://www.cuizb.top/myblog/article/1639579500
版权声明: 本博客所有文章除特别声明外,均采用 CC BY 3.0 CN协议进行许可。转载请署名作者且注明文章出处。
更多文章和干货请关注公众号
本文来自博客园,作者:Java技术债务,转载请注明原文链接:https://www.cnblogs.com/cuizb/p/16428546.html