0

0

Java并发编程中synchronized怎么用_底层机制解析

P粉602998670

P粉602998670

发布时间:2026-03-11 15:30:48

|

311人浏览过

|

来源于php中文网

原创

synchronized本质是对对象加锁:实例方法锁this,静态方法锁class对象;线程安全取决于锁对象是否一致及覆盖所有共享路径,需依状态共享范围合理选择实例锁或类锁。

java并发编程中synchronized怎么用_底层机制解析

怎么用 synchronized 锁住一个对象

直接在方法或代码块上加 synchronized,本质都是对某个对象加锁。普通实例方法加 synchronized,锁的是当前实例(this);静态方法加 synchronized,锁的是当前类的 Class 对象。

常见误用是以为「加了 synchronized 就线程安全」,其实关键看锁的对象是否一致、是否覆盖所有共享访问路径。

  • 多个线程调用同一个对象的 synchronized 实例方法 → 串行执行
  • 多个线程调用不同对象的相同 synchronized 实例方法 → 不互斥(锁对象不同)
  • 一个线程在 synchronized(this) 块里,另一个调用该对象的 synchronized 方法 → 互斥(锁同一对象)
  • 静态方法和 synchronized(YourClass.class) 等价,但和实例锁完全无关

synchronized(this) 和 synchronized(staticObject) 的区别

前者锁实例,后者锁类级别资源。如果要保护全局计数器、缓存、配置加载等跨实例共享的状态,必须用类锁,否则每个实例都有一把独立锁,起不到同步作用。

典型陷阱:在单例模式中误用 this 锁,而单例本身可能被反射/反序列化绕过,导致锁失效;更稳妥的是显式用 private static final Object LOCK = new Object()

立即学习Java免费学习笔记(深入)”;

IBM Watson
IBM Watson

IBM Watson文字转语音

下载
  • synchronized(this):适合保护当前对象内部状态(如 ArrayList 的 size、elementData)
  • synchronized(YourClass.class):适合初始化逻辑(如双重检查单例里的 instance == null 判断)
  • 避免用字符串字面量或外部传入对象作锁(如 synchronized("LOCK")),容易因字符串常量池或引用混用导致意外锁竞争

为什么 synchronized 不会死锁但可能饥饿

Java 的 synchronized 是可重入锁,同一线程可多次进入同一把锁,且 JVM 保证解锁顺序与加锁顺序相反。但它不提供公平性控制——默认非公平,先到不一定先得,高并发下可能某些线程长期拿不到锁(饥饿)。

  • 不会因为「自己锁自己」死锁(可重入性保障)
  • 但嵌套锁顺序不一致会真死锁:thread1 先锁 A 再锁 B,thread2 先锁 B 再锁 A → 必须统一加锁顺序
  • 没有超时机制:synchronized 无法像 Lock.tryLock(long, TimeUnit) 那样主动放弃,阻塞就是无限期等待
  • JVM 层面对锁做了优化(偏向锁→轻量级锁→重量级锁),但 JDK 15+ 已默认禁用偏向锁,实际多为轻量级锁(CAS + 自旋)或系统互斥量

底层到底发生了什么(HotSpot 简化视角)

每个 Java 对象头(Object Header)里有 Mark Word,synchronized 的加锁/解锁操作,本质是通过 CAS 修改 Mark Word 中的锁标志位和指向 Monitor 的指针。Monitor 是 C++ 实现的,包含 Owner、EntryList、WaitSet 等字段。

当锁竞争激烈时,JVM 会将轻量级锁膨胀为重量级锁,此时线程会挂起(park),由操作系统调度唤醒(unpark)。这个过程涉及用户态/内核态切换,开销远大于自旋。

  • 无竞争:偏向锁(已弃用)或轻量级锁(CAS 替换 Mark Word)→ 几乎无额外开销
  • 低竞争:自旋等待(spin)→ 节省上下文切换,但浪费 CPU
  • 高竞争:膨胀为重量级锁 → 线程进 EntryList 阻塞,唤醒依赖 OS
  • 调用 wait() 会释放锁并进入 WaitSetnotify() 只是将其移回 EntryList,不立即获得锁
public class Counter {
    private int count = 0;
    private static final Object CLASS_LOCK = new Object();

    public void increment() {
        synchronized (this) { // 锁实例
            count++;
        }
    }

    public static void resetAll() {
        synchronized (CLASS_LOCK) { // 锁类级别资源
            // 清空所有实例共用的缓存等
        }
    }
}

真正难的不是语法,是判断「哪段状态需要保护」「锁的粒度是否合理」「有没有隐式依赖其他锁」。比如在 synchronized 块里调用外部回调函数,就可能把锁的范围意外扩大,甚至引发死锁。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

254

2023.09.22

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

1089

2024.03.01

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1566

2023.10.24

字符串常量的表示方法
字符串常量的表示方法

字符串常量的表示方法:1、使用引号;2、转义字符;3、多行字符串;4、原始字符串;5、字符串连接;6、字符串字面量和对象;7、编码问题。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

143

2023.12.26

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

760

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

221

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1566

2023.10.24

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

649

2023.11.24

C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

3

2026.03.11

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 4.3万人学习

C# 教程
C# 教程

共94课时 | 11.1万人学习

Java 教程
Java 教程

共578课时 | 80.5万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号