悲观锁和乐观锁

目录

悲观锁 通常用在多写场景

Synchronized

底层原理

修饰代码块,锁的是给定对象

修饰方法

ReentrantLock

Synchronized和ReentrantLock比较

乐观锁 通常用在多读场景

CAS的问题


悲观锁 通常用在多写场景

悲观锁假设总是最坏的情况,每次去访问公共资源时,都认为可能会出现问题,共享资源可能会被其他线程修改,所以每次访问公共资源的时候,对其进行加锁。其他线程想要访问该资源,就要被阻塞,一直到上一条线程执行完毕释放锁。

Synchronnized和ReentrantLock都是悲观锁的实现。

问题:高并发场景下,可能会造成大量的锁阻塞,并且还有死锁问题。

Synchronized

底层原理

本质都是获取锁监视器monitor的过程,默认是非公平锁。

修饰代码块,锁的是给定对象

monitorenter指令是获取锁,如果锁计数器是0,则表示可以获取锁,获取锁之后,锁计数器+1。获取锁失败就进入阻塞队列,等待下一次时间片的抢夺。

monitorexit指令是持有锁的线程释放锁的指令,释放锁之后,锁计数器-1,其他线程就可以获取锁了。

修饰方法

修饰实例方法,锁的是当前对象

修饰静态方法,锁的是当前类

使用ACC_SYNCHRONNIZED来标识一个是一个同步方法,

ReentrantLock

原理:基于AQS,是一个可重入且独占锁,默认是非公平锁,可以通过构造器显式指定公平锁。

相比Synchronized,ReentrantLock 更灵活、更强大,增加了轮询、超时、中断、公平锁和非公平锁等高级功能。

Synchronized和ReentrantLock比较

1、都是可重入锁(递归锁),否则会造成死锁问题。

2、synchronized是基于JVM,而ReentrantLock是基于Jdk的API。

3、ReentrantLock比Synchronized增加了很多高级功能

等待可中断、可实现公平锁、可选择性通知

乐观锁 通常用在多读场景

乐观锁假设总是最好的情况,每次访问资源都不会认为会出现问题,不会加锁也不会阻塞,可以一直运行。每次去修改时,需要校验对应资源有没有被修改过,如果有,则重新执行修改逻辑,如果没有,就提交修改。

CAS就是典型的乐观锁。

CAS的问题

问题:高并发场景下,如果写操作比较多的话,可能会造成频繁失败和重试,CPU压力过大。

CAS问题:ABA问题——CAS每次去修改值的之后,如果预期值A被其他线程修改为B,再修改为A,这个过程当前线程是不知道的。

解决方案:使用版本号机制或时间戳或标记字段都可以。

CAS问题:循环消耗大,失败重试直到成功。

解决方案:限制重试次数,一般限制为3次

  • 16
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值