java 线程——乐观锁&悲观锁

乐观锁

适用场景

实现方式

版本号机制

CAS

悲观锁

适用场景

缺点  

相关文章

乐观锁

每次读取数据的时候总是认为不会被人拿数据,所以不去加锁,但是在更新的时候回去对比一下原来的值,看有没有被别人更改过。

适用场景

读操作比较多的时候,提高了吞吐量。

实现方式

版本号机制

在数据表中加入了版本号,当数据被修改是版本号加一,每次更新数据的时候比较版本号是否是刚刚的版本号,若是,则更新。否则,重试更新操作,直到成功。

CAS

CAS 操作中包含三个操作数 —— 需要读写的内存位置(V)、进行比较的预期原值(A)和拟写入的新值(B)。如果内存位置V的值与预期原值A相匹配,那么处理器会自动将该位置值更新为新值B。否则处理器不做任何操作。无论哪种情况,它都会在 CAS 指令之前返回该位置的值。(在 CAS 的一些特殊情况下将仅返回 CAS 是否成功,而不提取当前值。)CAS 有效地说明了“ 我认为位置 V 应该包含值 A;如果包含该值,则将 B 放到这个位置;否则,不要更改该位置,只告诉我这个位置现在的值即可。 ”这其实和乐观锁的冲突检查+数据更新的原理是一样的。

CAS 的 ABA 问题

《java 线程——乐观锁&悲观锁》

上图中,线程 1 感觉V 里面的值没有被改变,但其实线程2 已经改变了,只不过线程1检测不到,这样值保证了A 这个值没有被改变,但若是V 里面其他的值被改变,这就出现了错误。

ABA 问题的解决方案

加入版本号

悲观锁

每次读取数据的 时候都认为其他人会修改数据,所以读取数据的时候就加了锁,这样别人想拿的时候就会阻塞,直到这个线程释放锁。Synchronized 就是用悲观锁实现的。

适用场景

适合于更新操作比较频繁的情况

缺点  

  • 在多线程竞争下,加锁、释放锁会导致比较多的上下文切换和调度延时,引起性能问题。
  • 一个线程持有锁会导致其它所有需要此锁的线程挂起。
  • 如果一个优先级高的线程等待一个优先级低的线程释放锁会导致优先级倒置,引起性能风险。

相关文章

java 线程——偏向锁&轻量级锁&重量级锁

java 线程——可重入锁&不可重入锁

    原文作者:java锁
    原文地址: https://blog.csdn.net/Alyson_jm/article/details/82820103
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞