Synchronized为什么是重量级锁?

Synchronized被称作重量级锁主要是因为在锁被占用时,它依赖操作系统pthread_mutex_lock实现,导致线程在用户态与内核态之间切换,消耗更多资源。而ReentrantLock使用CAS操作和Unsafe.park(),减少了这种切换,因此相对轻量。即使ReentrantLock在阻塞线程时仍需内核介入,但总体开销较小。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Synchronized 是Java中的一种锁实现,很多资料中都有说这是一个重量级锁(对其有许多优化,轻量级锁、偏向锁等),但是剔除这些优化的情况下,为什么 Synchronized 是一个重量级锁呢?


以下的思考基于 RentrantLockSynchroinzed 展开

思考1 会不会是因为Synchronized关联了一个Monitor对象呢?

某面试官对我的回答: 这仅仅只是关联了一个对象,不足以让 Synchronized 称为重量级锁

思考2 会不会是因为维护了阻塞队列和等待队列呢?

不会,因为 ReentrantLockSynchronized 都有维护阻塞队列和等待队列


在我上网查阅了资料和问了大佬后,得出了以下的总结:

在这里插入图片描述
首先需要理解的是,当锁被占用的时候,Synchronized和ReentrantLock的区别是不大的。原因如下:

  • Synchronized可以通过关联的Moniter对象中的Owner发现锁已经被占用,然后直接阻塞当前线程
  • ReentrantLock通过锁状态state可以发现锁被占用,然后直接调用Unsafe.park()阻塞线程

当锁没有被占用,也就是说Moniter对象中的Owner == null 时,并且ReentrantLock中的state为0时,就会体现出的差别。

  • Synchronized加锁操作底层依赖操作系统的pthread_mutex_lock实现,当多个线程同时调用这个函数的时候,会让每一个线程都切换到内核态,由内核协调哪个线程获取到锁,哪些线程无法获取到锁。获取锁成功的线程会被唤醒,获取锁失败的线程会被内核进行阻塞,线程阻塞才能释放CPU资源,执行完才会从内核态转换为用户态。

  • ReentrantLock在加锁时会调用Unsafe.compareAndSwapInt(),这是操作系统指令上实现的原子性cas,其中不涉及内核态与用户态的切换。换而言之,ReentrantLock在Java层面维护锁的状态。ReentrantLock阻塞操作使用的是Unsafe.park(),其依赖操作系统的pthread_mute_trylock实现(pthread_mutex_lock的非阻塞版本,当获取不到锁时会直接返回,最终阻塞线程调用的是pthread_cond_wait),当多个线程同时竞争时,获取锁成功的线程不需要切换到内核态,可以直接运行,而其他线程会进入到内核态进行阻塞。

值得注意的是:尽管 ReentrantLock 不需要切换到内核去维护锁状态,但是在线程需要阻塞的情况下,内核态/用户态的切换还是无法避免的(线程的唤醒和挂起依旧是需要由内核进行的)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值