当前位置: 首页 > news >正文

孤舟笔记 并发篇七 synchronized和Lock到底啥区别?面试为什么年年都问这道题

文章目录

    • 先说结论:核心区别一览
    • synchronized:自动挡,省心但死板
    • Lock:手动挡,灵活但要自己负责
    • Condition:Lock 的杀手锏
    • synchronized 的逆袭:JVM 层面优化
    • synchronized vs Lock 全景
    • 回答技巧与点评
        • 标准回答
        • 加分回答
        • 面试官点评

个人网站

学 Java 并发的时候,你一定见过这对"双胞胎"——synchronizedLock。都是加锁,都能保证线程安全,那为啥要搞两套?面试官还特别喜欢问"它们的区别",你随口说一个"Lock 更灵活",面试官追问"灵活在哪",你就卡壳了。

今天咱们就把 synchronized 和 Lock 放在一起掰开了比,让你面试时能说个清清楚楚。

先说结论:核心区别一览

||| 维度 | synchronized | Lock(ReentrantLock) |
|||------|------|------|
||| 层面 | JVM 关键字 | JDK API 接口 |
||| 加锁方式 | 隐式加锁,进出自动 | 显式加锁,手动 lock/unlock |
||| 可中断性 | 不可中断 | lockInterruptibly() 可中断 |
||| 超时获取 | 不支持 | tryLock(timeout) 支持 |
||| 公平性 | 非公平锁 | 可选公平/非公平 |
||| 条件变量 | 只有一个 wait/notify | 多个 Condition 精准唤醒 |
||| 锁状态 | 无法判断是否获取到锁 | tryLock() 可判断 |
||| 释放锁 | 异常时自动释放 | 必须在 finally 中手动释放 |

一句话记住:synchronized 是自动挡,Lock 是手动挡——自动挡省心,手动挡灵活。

synchronized:自动挡,省心但死板

synchronized用起来特别简单,加个关键字就完事:

synchronized(obj){// 进入自动加锁,退出自动释放 👈balance-=100;}

你不需要手动释放锁,哪怕代码抛异常,JVM 也会保证锁被释放。这就是"自动挡"的好处——省心

但省心的代价是不灵活。你想中途放弃等锁?不行。你想设个超时?不行。你想精准唤醒某个等待线程?只能notifyAll()一把梭,把所有等着的线程都叫醒。

生活类比:synchronized就像自动门,人到门前自动开,人走自动关,但你没法控制它什么时候开、开多久。

Lock:手动挡,灵活但要自己负责

ReentrantLockLock接口最常用的实现类,用法稍微麻烦一点:

Locklock=newReentrantLock();lock.lock();// 手动加锁 👈try{balance-=100;}finally{lock.unlock();// 必须手动释放 👈 忘了就死锁!}

重点:unlock()必须放在finally块里。忘了释放锁,别的线程就永远等下去了。这是"手动挡"的代价——你得自己负责

但换来的灵活性非常强大:

1. 超时获取锁——不死等

if(lock.tryLock(3,TimeUnit.SECONDS)){// 3秒拿不到就放弃 👈try{/* 业务 */}finally{lock.unlock();}}

2. 可中断——等锁的时候能被打断

lock.lockInterruptibly();// 等锁期间可以被 interrupt() 打断 👈

3. 公平锁——先来先得

LockfairLock=newReentrantLock(true);// true = 公平锁 👈

synchronized只能是非公平锁,后来的线程可能"插队"先拿到锁。

Condition:Lock 的杀手锏

如果说tryLock和公平锁只是"锦上添花",那Condition就是 Lock 相比 synchronized 的杀手锏。

synchronized只有一把wait/notify,唤醒线程时没法指定是谁。但Lock可以创建多个Condition,精准唤醒:

Locklock=newReentrantLock();ConditionnotFull=lock.newCondition();// 队列没满条件 👈ConditionnotEmpty=lock.newCondition();// 队列没空条件 👈// 生产者:队列满了等"没满",放入后通知"没空"notFull.await();notEmpty.signal();// 精准唤醒消费者 👈// 消费者:队列空了等"没空",取出后通知"没满"notEmpty.await();notFull.signal();// 精准唤醒生产者 👈

synchronizednotifyAll()是大喇叭广播,Conditionsignal()是定向通知。生产者-消费者模型中,这个精准度差别太大了。

synchronized 的逆袭:JVM 层面优化

别以为synchronized就一无是处。JDK 6 之后,JVM 对synchronized做了大量优化:

  • 偏向锁:只有一个线程访问时,连 CAS 都省了
  • 轻量级锁:短时间竞争用 CAS 自旋,不阻塞
  • 重量级锁:竞争激烈才膨胀为操作系统互斥量

这些优化都是 JVM 自动完成的,你代码不用改。所以在竞争不激烈的场景,synchronized的性能并不比Lock差。

synchronized vs Lock 全景

synchronized 与 Lock 对比 全景 核心差异 ├── synchronized ── JVM 关键字,隐式加锁释放 │ ├── 自动释放锁(异常安全) │ ├── 不可中断、不可超时 │ ├── 只能非公平锁 │ └── 单条件变量(wait/notify) └── Lock ── JDK API,显式加锁释放 ├── 必须手动释放(finally 中 unlock) ├── 可中断(lockInterruptibly) ├── 可超时(tryLock) ├── 可选公平/非公平 └── 多条件变量(Condition) 选择建议 ├── 简单场景 → synchronized(代码简洁,自动优化) ├── 需要超时/中断/公平 → ReentrantLock └── 需要精准唤醒 → Lock + Condition 口诀:sync 自动省心用,Lock 灵活手动控, 超时中断公平锁,Condition 精准唤。

回答技巧与点评

标准回答

synchronized 是 JVM 层面的关键字,自动加锁释放锁,不可中断、不可超时、只能非公平;Lock 是 JDK 层面的 API 接口,需手动加锁释放,支持可中断、超时获取、公平锁选择,以及多个 Condition 精准唤醒。简单场景优先用 synchronized,需要灵活控制时用 Lock。

加分回答
  1. 设计哲学:synchronized 体现了"约定优于配置"的思想,用最简单的语法完成最常见的场景;Lock 体现了"显式优于隐式",把控制权交给开发者,适合复杂并发场景
  2. 性能边界:JDK 6 之后 synchronized 有偏向锁、轻量级锁等优化,低竞争场景性能不输 Lock。但高竞争场景下,Lock 的tryLock能避免线程长时间阻塞,整体吞吐量更优
  3. 进阶应用ReentrantReadWriteLock是 Lock 的另一个重要实现,读写分离,适合读多写少场景。synchronized 没有读写分离的能力
面试官点评

这道题考的是你对两种锁机制的全面理解和场景选择能力。只说"synchronized 自动、Lock 手动"太浅了。能展开讲 Condition 的精准唤醒、JVM 锁优化、以及 tryLock 在死锁避免中的作用,才能拿高分。如果能顺带提到 ReadWriteLock,说明你的知识面足够宽。

原文阅读


内容有帮助?点赞、收藏、关注三连!评论区等你 💪

http://www.cnnetsun.cn/news/2154048.html

相关文章:

  • 从AMBA到AXI:聊聊ARM片上总线演进史,以及为什么FPGA设计离不开它
  • GR-RL框架:几何推理与强化学习融合的机器人精密操作方案
  • 开源TinyUSB协议栈深度体验:在ESP32-S3上实现MSC+CDC,打造你的全能USB“瑞士军刀”
  • 告别遥控器!用键盘鼠标+ADB无线调试华为悦盒EC6108V9,解锁Linux式操作体验
  • 多智能体协作系统CubSwarm深度解析:Harness工程与品牌记忆设计
  • 从Apollo 8到Apollo 17:Virtual AGC软件版本完整对比指南
  • 仓储物流场景的工业配送和工业AMR品牌应该怎么选?
  • ARM嵌套虚拟化技术:NVHCRX_EL2寄存器详解与应用
  • 零信任时代的数据合规终极指南:Electric SQL实现GDPR与本地化同步的完整解决方案
  • 如何创建仅在首次订阅时执行一次计算的 RxJS 懒加载 Observable
  • 004、四元数基础与运算
  • 10分钟掌握Laravel数据库缓存:从查询优化到性能倍增
  • 17_《智能体微服务架构企业级实战教程》开发框架搭建之安装项目依赖
  • linux drm 行场同步
  • 这绝对是2026最全CTF入门指南!零基础小白如何入门CTF,看这一篇就够了(附学习笔记、靶场、工具包)
  • 100K并发下的成本革命:uWebSockets边缘计算性能价格比深度分析
  • 从盲签名到群签名:手把手用Python模拟隐私保护签名(附代码避坑指南)
  • semi-utils深度解析:高效的批量图片处理自动化方案
  • real-anime-z实战手册:批量生成+自动重命名+本地文件夹导出完整脚本
  • 齿轮箱轴承故障诊断与寿命预测【附代码】
  • 九号公司第一季营收58.7亿:同比增15% 净利2亿
  • 【教学类-160-14】20260425 AI视频培训-练习014“豆包AI视频《月下枯蔷(哥特风)》+豆包图片风格:油画”
  • 华硕笔记本性能调校终极指南:G-Helper完全替代Armoury Crate
  • 十大Web安全扫描工具
  • React Native集成AI开发实战:从OpenAI API到移动端智能应用
  • Antenna:插件化声明式数据采集框架的设计与实战
  • 智能体可观测性实践:用Agent-Lens实现LLM智能体全链路追踪与评估
  • 从同步阻塞到毫秒级响应,PHP 8.9 纤维协程落地全链路拆解,手把手带跑通电商秒杀场景
  • 构建高价值技能库:从硬技能到元技能的终身学习策略
  • 图神经网络域融合迁移诊断【附代码】