专业的JAVA编程教程与资源

网站首页 > java教程 正文

JAVA面试|公平锁、非公平锁区别以及应用场景

temp10 2025-06-23 21:45:59 java教程 2 ℃ 0 评论

公平锁和非公平锁是并发编程中两种常见的锁策略,理解它们的区别需要结合生活场景和底层原理来讲解。


JAVA面试|公平锁、非公平锁区别以及应用场景

一、通俗比喻理解

1. 公平锁

场景:银行排队叫号机。假设银行有10个窗口,但每次只开放1个窗口。所有客户必须按取号顺序办理业务,即使窗口空闲时也必须等待叫号。

特点:先来的人一定先被服务,严格按顺序。

2. 非公平锁

场景:地铁抢座位。地铁到站时,所有等待的乘客一拥而上,谁挤得快谁先坐,不管谁先到站台。

特点:后来的可能“插队”成功,效率更高但可能不公平。


二、技术原理对比

1. 公平锁

当一个线程尝试获取锁时,会先检查等待队列(AQS中的CLH队列)是否有其他线程在等待。如果队列为空,或当前线程是队列的第一个,则获取锁成功。如果队列中有其他线程,则当前线程进入队列尾部排队。

2. 非公平锁

线程尝试获取锁时,直接通过CAS(Compare-And-Swap)抢占锁,不检查队列是否有等待线程。如果锁空闲,立即获取成功。如果锁被占用,再进入队列排队。


三、核心区别总结

特性

公平锁

非公平锁

顺序性

严格按请求顺序分配锁

允许“插队”,后申请的线程可能先获取锁

性能

吞吐量低(需要频繁线程切换)

吞吐量高(减少线程切换)

饥饿问题

不会出现线程饥饿

可能发生线程饥饿

实现复杂度

更复杂(需维护队列顺序)

更简单(直接CAS抢锁)


四、应用场景

1. 公平锁适用场景

需要严格顺序性:例如订单系统,确保先下单的用户先处理,避免资源被长时间占用。

防止线程饥饿:在任务执行时间差异大的场景(如长任务和短任务混合),避免短任务被长任务“饿死”。

2. 非公平锁适用场景

高吞吐需求:例如Web服务器的并发请求处理,减少线程切换开销,提升性能。

锁持有时间短:如果线程释放锁后很快再次申请锁(如自旋锁),非公平锁能减少排队等待时间。


五、性能差异原因

公平锁的额外开销:每次获取锁时需检查队列状态(hasQueuedPredecessors()),且唤醒线程需要从队列头部开始,涉及更多上下文切换。

非公平锁的优势:线程释放锁后,新来的线程可能直接获取锁,避免唤醒队列中线程的开销(减少线程切换)。


六、实战建议

默认选择非公平锁:如Java的ReentrantLock默认是非公平锁,因为大多数场景吞吐量更重要。

仅在必要时用公平锁:当业务明确要求顺序性(如交易系统、排队系统)时,才使用公平锁。

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表