不建议在高并发场景下使用synchronized?

今天在查找资料时发现了这个问题:为什么不建议在高并发场景下使用 synchronized?

通过这个问题也可以深入理解一下 synchronized!这首先我们要了解 高并发场景的特点 以及 synchronized 底层加锁的原理 是怎样的!

首先说一下 synchronized 底层加锁的原理:

synchronized 在 JDK1.6 之后引入了锁的优化,随着多线程竞争的激烈程度不同,使用的锁也不同

  • 当没有线程竞争,此时为 无锁 状态

  • 如果只有一个线程不停访问同步代码块,此时会使用 偏向锁

  • 如果有两个以上线程并发访问,偏向锁会撤销,并升级为 轻量级锁 (偏向锁在 JDK15 之后就被废弃了,因为撤销带来性能开销比较大)

  • 如果在轻量锁 CAS 自旋达到一定次数还没有拿到锁,就会撤销轻量级锁,升级为 重量级锁 ,其实重量级锁的开销是比较大的。

在高并发场景下,并发度肯定是比较高的,不建议使用 synchronized 的 原因主要有以下几点:

  • 由于并发度比较高,因此 synchronized 一定会升级到重量级锁,但是重量级锁的性能是不太高的,因为线程要阻塞再唤醒,需要用户态和内核态之间切换。

  • synchronized 没有读写锁优化。

  • synchronized 不能对线程唤醒,也就是线程如果获取不到锁的话会一直阻塞。

在使用 synchronized 的时候,一定要 直接将偏向锁给禁掉 ,因为大多数情况下,偏向锁都需要撤销升级为轻量级锁,而偏向锁的撤销性能是比较差的!

所以如果优化的话,对于第一个点来说,将等待线程阻塞再唤醒,个人感觉优化空间不大

第二个点就是读写锁的优化,读读之间不互斥,大幅度增强 读多写少 场景下的性能!

第三个点就是需要一个 tryLock(timeout) 功能,在指定时间获取不到锁的时候,可以直接将线程超时了,不去拿锁了。

为什么说需要 tryLock(timeout) 这个功能呢?

假设这样一种场景,有一个任务在某个时间点可能多个线程同时要来执行,但是只要有一个线程执行完毕之后,其他线程就不需要执行了。

那么假设在这个需要执行任务的时间点,大量线程同时过来执行,也就是大量线程都进入阻塞队列等待获取锁,第一个线程拿到锁执行任务之后,此时后边的线程都不需要执行该任务了,但是由于没有这个超时功能,导致后边的线程还需要在队列中等待获取锁,再一个个进入同步代码块,发现任务已经执行过了,不需要自己再执行了,之后再退出同步代码块。

因此这个 tryLock(timeout) 的作用就是 将大量线程的串行操作转为并行操作 ,大量线程发现指定时间内获取不了锁了,直接超时,不获取锁了,这样后边的线程再来看就发现任务已经执行过了,不需要再去获取锁执行任务了。

这里 tryLock(timeout) 的情况只是举一个特殊的情况,其实是参考了分布式环境下,更新 Redis 缓存时会出现这种情况,但是在分布式环境下肯定不会使用 synchronized ,因此这里主要是举个例子说一下 tryLock 的作用!

上边主要说了 synchronized 的缺点,可以通过各种问题来引发自己的思考,让自己对 synchronized 的理解更加深入。

一般在写项目使用分布式锁还是多一些,毕竟高并发项目肯定不会使用单节点部署,

而单机项目的话,一般也不会追求极致的性能,所以使用 synchronized 也没有什么问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值