You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Lock与synchronized的区别及选型:面试疑问解答

嘿,我太懂你这种困惑了——乍一看Lock和synchronized好像都能搞定线程同步,感觉随便用哪个都能完成任务,面试被问到的时候总怕踩不到面试官的点。其实它们核心目标一致,但细节差异和适用场景的区别,才是面试官真正想考察的点。

Lock vs synchronized:核心区别拆解

虽然都用来解决线程安全问题,但二者在使用方式、功能灵活性上差得不少:

  • 使用灵活性与锁管理
    synchronized是Java内置关键字,用法非常固定:要么修饰整个方法,要么包裹一段代码块。它最大的优点是自动释放锁——不管代码正常执行完毕还是抛出异常,JVM都会帮你释放锁,完全不用手动操心。但缺点也很明显:太死板,一旦进入等待锁的状态就没法中断,也没法指定等待超时时间。

    而Lock是java.util.concurrent.locks包下的接口,必须手动调用lock()加锁,并且一定要在finally块里调用unlock()释放锁(不然很容易导致锁泄漏)。但这份“麻烦”换来了极强的灵活性:比如可以用tryLock()尝试非阻塞获取锁(拿不到锁就直接去做别的事),用lockInterruptibly()允许中断等待锁的线程,还能给tryLock(long timeout, TimeUnit unit)指定超时时间,这些都是synchronized做不到的。

  • 锁的公平性
    synchronized默认是非公平锁,而且没有任何方式能改成公平锁——也就是说,线程获取锁的顺序是随机的,可能会出现“饥饿”情况(某个线程一直抢不到锁)。

    而Lock的典型实现ReentrantLock,可以在构造时传入true参数(new ReentrantLock(true))变成公平锁,让等待时间最久的线程优先获取锁,适合对线程执行顺序有要求的场景。

  • 可重入性
    这点二者是一致的:同一个线程可以多次获取同一个锁,不会出现自己把自己卡死的情况。比如synchronized修饰的递归方法,或者Lock连续调用多次lock(),只要unlock()的次数和lock()对应就行。

  • 性能表现
    早期Java版本里,synchronized的性能确实不如Lock,但从Java 6开始,JVM给synchronized加了一堆优化(偏向锁、轻量级锁、自旋锁等),现在绝大多数场景下,二者的性能差距已经可以忽略不计。只有在极高并发、锁竞争特别激烈的场景,Lock的某些实现可能会略占优势,但日常开发不用过度纠结这点。

优先选择哪个?看场景下菜

没有绝对的“更好”,只有更适合的:

  • 优先用synchronized:如果是简单的同步场景(比如普通方法同步、小范围代码块同步),synchronized绝对是首选。它代码简洁,不用手动管理锁释放,出错概率低,而且JVM的自动优化也能帮你省不少事,可读性还高——毕竟少写一行代码就少一个潜在bug。

  • 必须用Lock的场景:当你需要synchronized提供不了的功能时,就得上Lock:

    • 需要尝试获取锁失败后直接执行其他逻辑(用tryLock())
    • 需要中断正在等待锁的线程
    • 需要给获取锁设置超时时间,避免线程无限等待
    • 需要公平锁来避免线程饥饿
    • 需要多个条件变量(Condition)实现复杂线程通信(比如多生产者多消费者场景下的精准唤醒)

说白了,它们是互补关系,不是替代关系。面试时把这些差异和适用场景讲清楚,面试官就知道你不是只会机械使用,而是理解了并发编程的本质。

内容的提问来源于stack exchange,提问作者dead programmer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 04:05:39