详解Java中常见的锁

Java 中的锁

乐观锁与悲观锁

乐观锁

乐观锁 是一种乐观思想,即认为读多写少,遇到并发写的可能性低,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,采取在写时先读出当前版本号Version,然后加锁操作(比较跟上一次的版本号,如果一样则更新),如果失败则要重复读-比较-写的操作。

java中的乐观锁基本都是通过CAS操作实现的,CAS是一种更新的原子操作,比较当前值跟传入值
是否一样,一样则更新,否则失败

悲观锁

悲观锁 是就是悲观思想,即认为写多,遇到并发写的可能性高,每次去拿数据的时候都认为别人会修
改,所以每次在读写数据的时候都会上锁,这样别人想读写这个数据就会block直到拿到锁。

java中的悲观锁就是Synchronized,AQS框架下的锁则是先尝试cas乐观锁去获取锁,获取不到才会转换为悲观锁,如RetreenLock。

CAS(Conmpare And Swap)

在计算机科学中, 比较和交换 (Conmpare And Swap)是用于实现多线程同步的原子指令,是一种无锁原子算法。

CAS的原理在这里插入图片描述

  • 它将内存位置的内容与给定值进行比较,只有在相同的情况下,将该内存位置的内容修改为新的给定值。
  • 操作结果必须说明是否进行替换; 这可以通过一个简单的布尔响应(这个变体通常称为比较和设置),或通过返回从内存位置读取的值来完成。
  • 比较和交换 作为单个原子操作完成, 原子性保证新值基于最新信息计算; 如果该值在同一时间被另一个线程更新,则写入将失败。
    在这里插入图片描述

仅当 V 值等于 A 值时,才会将 V 的值设为B,如果 V 值和A值不同,则说明已经有其他线程做了更
新,则当前线程则什么都不做。最后,CAS 返回当前 V 的真实值。CAS 操作时抱着乐观的态度进
行的,它总是认为自己可以成功完成操作。

CAS的局限性

  1. 循环时间长开销大:CAS长时间自旋不成功,给CPU带来很大的性能开销。
    解决方法:JVM能支持pause指令,效率会有一定的提升。
  2. 只能保证一个共享变量的原子操作:对多个共享变量操作时,不能保证原子性。
    解决方法:加锁;共享变量合并成一个共享变量

死锁

造成死锁的条件

  1. 互斥条件:一个资源(临界资源)每次只能为一个线程使用,而且使用期间是互斥的。
  2. 不可抢占的条件:一个线程已经占有资源,未经本线程释放的情况下,其它线程不能强行剥夺。
  3. 占有且申请条件:(部分分配条件)线程投入时,不是一次性申请所需资源,而是运行中按需要临时动态地申请。
  4. 循环等待条件:系统中几个线程形成循环地等待对方所占用资源的关系。

如何避免死锁

预防死锁有一个基本思想:要求线程申请资源时遵循某种协议,从而打破产生死锁的四个条件中的一个或几个,从而保证系统不会进入死锁状态。

  1. 减小了锁定的范围,避免发生交叉访问
  2. 涉及到要同时申请两个锁的方法中,总是以相同的顺序来申请锁
  3. 避免使用阻塞锁,我们可以使用Reentrant lock,也是可以避免死锁的
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值