什么是悲观锁和乐观锁? - Java技术债务

悲观锁是将资源锁住,等一个之前获得锁的线程释放锁之后,下一个线程才可以访问。

乐观锁采取了一种宽泛的态度,通过某种方式不加锁来处理资源,可以使用版本号version和CAS算法 实现,性能较悲观锁有很大的提高。乐观锁适用于多读的应用类型,这样可以提高吞吐量

CAS算法

CAS全拼又叫做compareAndSwap,从名字上的意思就知道是比较交换的意思

它包含 3 个参数 CAS(V,E,N),V表示要更新变量的值,E表示预期值,N表示新值。仅当 V值等于E值时,才会将V的值设为N,如果V值和E值不同,则说明已经有其他线程做两个更新,则当前线程则什么都不做。最后,CAS 返回当前V的真实值。

它涉及到三个操作数:内存值、预期值、新值

cas是一种基于锁的操作,而且是乐观锁。

CAS机制的优点

一开始在文中我们曾经提到过,cas是一种乐观锁,而且是一种非阻塞的轻量级的乐观锁,什么是非阻塞式的呢?其实就是一个线程想要获得锁,对方会给一个回应表示这个锁能不能获得。在资源竞争不激烈的情况下性能高,相比synchronized重量锁,synchronized会进行比较复杂的加锁,解锁和唤醒操作。

乐观锁的缺点:

1、ABA问题

解决办法:

JDK 1.5 以后的 AtomicStampedReference 类就提供了此种能力,其中的compareAndSet 方法就是首先检查当前引用是否等于预期引用,并且当前标志是否等于预期标志,如果全部相等,则以原子方式将该引用和该标志的值设置为给定的更新值。

2、循环时间长导致cpu的开销大

自旋CAS如果一直没有获取锁或一直等待。

解决办法:

如果JVM支持处理器的PAUSE指令,两个作用:1、延长流水线执行指令(时间取决于实现的版本),使CPU不会消耗过多的资源;2、避免退出循环时因内存顺序冲突引起的CPU流水线被清空。

3、只能保证一个共享变量的原子操作

CAS 只对单个共享变量有效,当操作涉及跨多个共享变量时CAS 无效

解决办法:

JDK1.5后AtomicStampedReference类确保引用对象之间的原子性,可以把多个变量放在一个对象里来进行 CAS 操作.所以我们可以使用锁或者利用 AtomicReference 类把多个共享变量合并成一个共享变量来操作。

   登录后才可以发表呦...

专注分享Java技术干货,包括
但不仅限于多线程、JVM、Spring Boot
Spring Cloud、 Redis、微服务、
消息队列、Git、面试题 最新动态等。

想交个朋友吗
那就快扫下面吧


微信

Java技术债务

你还可以关注我的公众号

会分享一些干货或者好文章

Java技术债务