简述Java中synchronized关键字的底层工作原理

在Java中,synchronized 关键字是一个重要的同步机制,用于控制多线程对共享资源的访问,以防止并发问题。了解 synchronized 的底层工作原理,可以帮助我们更好地编写线程安全的代码。synchronized 关键字可以应用于方法或者代码块,其底层实现依赖于Java虚拟机(JVM)中的监视器锁(Monitor Lock)或内部锁。

1. 锁的获取和释放

当线程进入一个 synchronized 方法或代码块时,它会自动获取锁。当线程离开 synchronized 方法或代码块时,无论是通过正常路径返回还是通过抛出异常,它都会自动释放锁。

2. 锁的类型

  • 轻量级锁:当没有竞争出现时,JVM会使用轻量级锁。这种锁利用CAS(比较并交换)操作,试图不暂停持有锁的线程的执行,而是通过在对象头上的标记字段中记录锁的状态来实现。
  • 重量级锁:当锁竞争激烈时,轻量级锁会升级为重量级锁。这种锁会使其他试图进入同步代码块的线程进入阻塞状态。

3. 对象头和锁状态

Java对象在内存中有一个对象头部,其中包含了锁的信息。根据锁的状态,对象头部的标记字段会有不同的设置:

  • 无锁状态:没有线程持有锁。
  • 偏向锁:一种优化手段,偏向第一个获取它的线程,进入同步块时不需要真正的竞争锁。
  • 轻量级锁:在无实际竞争的情况下使用CAS设置锁定状态。
  • 重量级锁:当有多个线程竞争同一个锁时,锁会升级到重量级锁,相关线程可能会被挂起。

4. 锁的升级过程

  • 初始状态是无锁。
  • 当第一个线程访问同步块时,锁可以升级为偏向锁。
  • 如果另一个线程尝试访问同步块,偏向锁可以脱离偏向模式并升级为轻量级锁。
  • 如果竞争加剧,轻量级锁会升级为重量级锁。

5. 监视器锁和等待/通知机制

JVM内部使用监视器锁来实现 synchronized。监视器锁包含两个队列:等待队列和阻塞队列。等待队列用于存放调用了wait()方法的线程,阻塞队列用于存放尝试获取锁但未成功的线程。当锁被释放时,来自阻塞队列的线程将有机会获取锁,而来自等待队列的线程则需要等到特定条件满足并收到notify()notifyAll()调用。

总结

synchronized 的底层实现复杂且高效,通过锁的不同状态和锁升级机制,JVM可以在运行时根据具体情况调整同步策略,从而提供良好的性能和线程安全保障。

相关推荐
zzywxc78712 分钟前
详细探讨AI在金融、医疗、教育和制造业四大领域的具体落地案例,并通过代码、流程图、Prompt示例和图表等方式展示这些应用的实际效果。
开发语言·javascript·人工智能·深度学习·金融·prompt·流程图
浮灯Foden25 分钟前
算法-每日一题(DAY13)两数之和
开发语言·数据结构·c++·算法·leetcode·面试·散列表
淡海水39 分钟前
【原理】Struct 和 Class 辨析
开发语言·c++·c#·struct·class
Q_Q196328847543 分钟前
python的电影院座位管理可视化数据分析系统
开发语言·spring boot·python·django·flask·node.js·php
该用户已不存在1 小时前
OpenJDK、Temurin、GraalVM...到底该装哪个?
java·后端
杜子不疼.1 小时前
《Python学习之第三方库:开启无限可能》
开发语言·python·学习
TT哇1 小时前
@[TOC](计算机是如何⼯作的) JavaEE==网站开发
java·redis·java-ee
Tina学编程1 小时前
48Days-Day19 | ISBN号,kotori和迷宫,矩阵最长递增路径
java·算法
青川入梦2 小时前
MyBatis极速通关上篇:Spring Boot环境搭建+用户管理实战
java·开发语言·mybatis
执子手 吹散苍茫茫烟波2 小时前
leetcode415. 字符串相加
java·leetcode·字符串