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

synchronized的一些思考

1. synchronized的可见性

加锁时:线程会清空工作内存中共享变量的值,从主内存重新加载最新值到工作内存。
解锁时:线程会将工作内存中修改后的共享变量值强制刷新到主内存。
Java 的happens-before原则明确规定:一个线程解锁监视器的操作,happens-before 于后续线程对同一个监视器的加锁操作。
晚上突然对happens-before原则有了新的认识,这是不是就是代码重排序时的if else,满足了这些规则,则不允许重排序

2. 加锁和解锁是怎么做的

JVM为每个锁对象关联一个monitor,monitorenter和monitorexit字节码指令
Monitor { int count; // 锁的重入计数器 Thread owner; // 当前持有锁的线程 Queue EntrySet; // 等待获取锁的线程队列 Queue WaitSet; // 调用wait()后等待被唤醒的线程队列 }
synchronized的加锁 / 解锁本质是对Monitor 的获取与释放,通过控制线程对 Monitor 的竞争,结合工作内存与主内存的同步机制,实现了线程安全的三大特性:原子性(互斥执行)、可见性(内存同步)、可重入性(计数器机制)。

3. 可重入性如何处理父子类

无论子类是否重写父类的synchronized方法,只要通过子类实例调用父类的synchronized方法,锁对象都是子类实例本身。
非静态synchronized方法的锁对象是this,而this永远指向 “当前实例”。
静态方法的锁对象是类本身。

4. EntrySet 和 WaitSet 的唤醒机制

EntrySet(获取锁的等待队列)

  • 当持有锁的线程释放锁(计数器归 0)时,JVM 会唤醒EntrySet中阻塞的线程。
  • 被唤醒的线程会立即进入锁竞争状态,谁能抢到锁取决于底层操作系统的线程调度机制(通常是抢占式,优先级高的线程可能更先获得调度)。
  • 注意:唤醒操作不保证 “公平性”,即先进入队列的线程不一定先获得锁(非公平锁特性)。
    WaitSet(调用 wait () 后的等待队列)
  • 线程调用wait()后会释放锁并进入WaitSet,需等待其他线程调用notify()/notifyAll()唤醒。
  • notify()会随机唤醒WaitSet中的一个线程,notifyAll()会唤醒所有线程。
  • 被唤醒的线程不会直接获得锁,而是先进入 EntrySet 队列,与其他线程一起重新竞争锁(同样是抢占式)。

5. 唤醒后的锁竞争

被唤醒的线程不会直接获得锁,而是进入就绪状态,参与锁的重新竞争:竞争的核心是修改 Monitor 的owner和count:谁能成功将owner设为自己并将count置 1,谁就获得锁。竞争结果由操作系统的线程调度器决定(抢占式),优先级高的线程可能更先获得调度,但无绝对保证。未抢到锁的线程会重新进入EntrySet,继续阻塞等待下一次唤醒。
synchronized的EntrySet唤醒逻辑是非公平的,体现在:

  • 新线程可能插队:即使EntrySet中有等待的线程,新到达的线程仍可能直接抢到锁(无需进入队列)。
  • 唤醒顺序不保证:EntrySet中的线程唤醒顺序与它们进入队列的顺序无关,先阻塞的线程可能后被唤醒。

6. 唤醒顺序不保证

EntrySet本质是一个无序的等待集合(而非严格的 FIFO 队列)

  • 当线程阻塞时,会被添加到集合的任意位置(而非必须尾部)。
  • 当唤醒时,JVM 会从集合中随机或按某种非顺序规则选择线程(如选择第一个找到的线程,或基于线程优先级筛选),而非按入队顺序选择。
    为了最大化性能,避免为保证公平性而引入的额外开销
  • 减少数据结构维护成本
  • 避免 “唤醒 - 阻塞” 的恶性循环
  • 与synchronized的非公平性设计一致

7. 非就绪态线程为什么不会被操作系统调度

操作系统通过线程状态标记区分是否可调度,阻塞态线程不在就绪队列中,自然不会被调度。
等待特定事件唤醒:阻塞态的线程会关联一个 “等待事件”(如锁释放),当事件发生时(如 JVM 触发唤醒),操作系统会将其从阻塞态转为就绪态,重新加入就绪队列,此时才可能被调度。

8. 非抢占式的缺点

非抢占式的 “致命缺陷”:无法解决 “线程饥饿” 与 “响应性” 问题
抢占式的 “补救措施”:通过 “锁优化” 减少无效切换

  • JVM 层面:减少 “不必要的唤醒” 和 “阻塞”;轻量级锁
  • 操作系统层面:通过 “调度策略” 优先调度 “更可能拿到锁的线程”;A持有锁,A优先级++,A释放锁,优先唤醒等待锁的B
    抢占式调度模型—— 它不是 “完美无开销” 的,但却是 “在资源开销、响应性、公平性之间平衡的最优解”。
http://www.wxhsa.cn/company.asp?id=2339

相关文章:

  • 题解:CF2133C The Nether
  • 实变函数1
  • css背景
  • 一元二次方程难题1
  • ios系统和windows系统的区别
  • 2025.9.11 刷题日记
  • C#学习第十 一天 022 事件最后一章
  • 元推理无需数据训练,只需数据检索和验证,成本极大降低,且校验后的数据就是数据资产和规范
  • 如何在Typescript中使用泛型约束
  • 集训总结(五)
  • 使用Android(Kotlin)+ ML Kit:移动端英文数字验证码识别实战
  • Typescript中的泛型
  • windows软件入门指南
  • LLM 生成代码执行代码
  • 网络爬虫(web crawler) - 指南
  • css样式与选择器
  • 水库运行综合管理平台
  • Nginx配置文件介绍
  • 《提问的艺术》笔记:(2025/9/12)
  • 各模态优势(可见光保留细节纹理,红外突出目标)
  • 复习vue
  • 眼下硬件是足够用的,最大的问题还是AI模型本身的能力不太够。没办法让硬件真正用起来,比如AI难以很好地控制灵巧手
  • 深入理解C语言---函数
  • Ubuntu 点击任务栏应用程序最小化
  • Agent Sudo | Writeup | TryHackMe
  • UT_HASH
  • 使用helm安装APISIX
  • 决策单调性
  • 2025 国内 HR SaaS 系统深度分析:Moka 引领 AI 变革
  • 学生信息管理系统案例初步分析报告