Condition和synchronized区别总结

关键区别详解

1、等待集的个数与等待条件(最核心的区别)

1.1、这是两者最本质的区别,决定了它们在处理复杂同步问题时的能力。

synchronized:单一等待集

一个锁对象(monitor)只有一个隐式的等待队列。所有调用wait()的线程都在这个队列里等待。当调用notify()时,JVM会从整个等待集中随机唤醒一个线程;notifyAll()会唤醒所有等待线程。

问题:

如果因为不同的条件而等待(例如,生产者等待“队列非满”,消费者等待“队列非空”),它们都在同一个队列里。使用notifyAll()会唤醒所有等待的线程(包括生产者和消费者),但被唤醒的线程可能发现自己的等待条件仍未满足(例如,唤醒了生产者但队列还是满的),这会导致“虚假唤醒”或不必要的竞争,效率较低。

Lock+ Condition:多个等待集

一个 Lock可以创建多个 Condition对象(例如:Condition notEmpty = lock.newCondition(); Condition notFull = lock.newCondition();)。这样,可以将等待不同条件的线程放到不同的队列中。

优势:

生产者可以在notFull条件上等待(notFull.await()),消费者可以在notEmpty条件上等待(notEmpty.await())。当生产者生产了一个数据后,它只需要调用notEmpty.signal()来精确唤醒一个在“队列非空”条件上等待的消费者线程,而不会误唤醒其他生产者。这大大提高了效率和精确度。

1.2、功能特性

synchronized:

简单易用:语法简洁,不需要手动释放锁,JVM 会保证锁的释放,避免了死锁的可能性(在代码块结束时自动释放)。
功能有限:不支持尝试获取锁、超时获取锁、中断正在等待获取锁的线程。

Lock+ Condition:

功能丰富:
尝试获取锁:tryLock(),获取不到立即返回false,不会阻塞。
超时获取锁:tryLock(long time, TimeUnit unit),在指定时间内获取不到则返回。
可中断的锁获取:lockInterruptibly(),在等待锁的过程中可以响应中断。
需要手动管理:必须在 finally块中手动调用 unlock()来释放锁,否则容易导致死锁。

性能

在早期版本中,synchronized是重量级锁,性能远差于Lock。但经过JDK 的不断优化(如偏向锁、轻量级锁、自旋锁等),现在两者的性能差距已经非常小,甚至在很多场景下synchronized性能更优。
因此,性能不再是选择的主要依据。选择的关键在于功能的灵活性和对复杂场景的建模能力。

如何选择?

优先使用 synchronized:
对于大多数简单的同步场景。
当你需要简单、不易出错的代码(自动释放锁)。
在性能不是极端敏感的情况下。

考虑使用 Lock+ Condition:

当需要实现复杂的同步逻辑时,例如有界队列、复杂的资源池管理等。
当需要多个条件谓词(多个等待集)来实现更精细的线程通知时。
当需要尝试获取锁、超时、可中断等高级特性时。

一句话总结:synchronized是“瑞士军刀”,简单通用;而 Lock+ Condition是“专业工具套装”,功能强大且灵活,用于解决更复杂的问题。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

信仰_273993243

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值