登录
首页 >  文章 >  java教程

synchronized 代码块嵌套实战应用详解

时间:2026-05-13 12:09:52 166浏览 收藏

本文深入剖析了synchronized代码块嵌套的核心要点:嵌套本身并非问题,真正危险的是锁对象不唯一或加锁顺序不统一所引发的死锁风险;强调必须使用final且共享的锁对象、严格遵循全局一致的加锁顺序、合理缩小同步范围以实现逻辑分层,并在多锁协作场景下优先推荐ReentrantLock的tryLock超时机制——既提升并发安全性,又增强系统健壮性与可维护性。

如何应用代码块嵌套实战控制 synchronized 关键字在变量块上的同步范围

直接说重点:用 synchronized(变量) 做代码块嵌套,核心不是“能不能嵌”,而是“锁对象是否一致、顺序是否统一”。嵌套本身不危险,危险的是在不同锁对象之间无序切换——这会快速引发死锁。

明确锁对象的唯一性

变量作为锁,必须是同一个实例对象。比如:

  • private final Object lock1 = new Object(); 定义的锁,多个线程都用它,才真正互斥
  • 如果每次 new 一个新对象当锁(如 synchronized(new Object())),等于没锁——每个线程拿的都是自己的锁
  • 共享变量如果是可变引用(比如被重新赋值过),锁就失效了;建议声明为 final

嵌套时只用同一把锁,避免交叉

不要出现这种写法:

  • synchronized(lockA) { ... synchronized(lockB) { ... } }
  • synchronized(lockB) { ... synchronized(lockA) { ... } }

两个线程分别按不同顺序进入,立刻形成环路等待。正确做法是:所有涉及 lockA 和 lockB 的操作,强制约定顺序——比如“永远先 lockA,再 lockB”。

缩小同步范围,嵌套只为逻辑分层

嵌套不是为了“套着锁”,而是为了在大逻辑里精准控制小临界区。例如:

  • 外层锁 account(保护账户余额)
  • 内层只对 logList 加锁(仅保护日志追加,不阻塞余额计算)
  • 关键:logList 的锁对象要独立且 final,不能和 account 锁混用

这样既隔离了资源,又避免长时持锁。

替代方案:优先考虑 tryLock + 超时

真需要多锁协作时,synchronized 很难优雅处理。更稳妥的做法是换用 ReentrantLock

  • lock.tryLock(3, TimeUnit.SECONDS) 主动设超时
  • 失败就释放已持锁、回退重试或报错,不卡死
  • 配合 lock.lockInterruptibly() 支持中断响应

这比靠人工盯住嵌套顺序更可靠。

终于介绍完啦!小伙伴们,这篇关于《synchronized 代码块嵌套实战应用详解》的介绍应该让你收获多多了吧!欢迎大家收藏或分享给更多需要学习的朋友吧~golang学习网公众号也会发布文章相关知识,快来关注吧!

资料下载
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>