Java 中的 synchronized 与 Lock:深度对比、使用场景及高级用法

💡 前言

在多线程并发编程中,线程安全问题始终是开发者需要重点关注的核心内容之一。Java 提供了多种机制来实现同步控制,其中最常用的两种方式是:

  • 使用 synchronized 关键字
  • 使用 java.util.concurrent.locks.Lock 接口(如 ReentrantLock

虽然两者都能实现线程同步功能,但它们在使用方式、灵活性、可扩展性以及性能优化方面存在显著差异。

本文将从底层原理、语法结构、使用场景、优缺点、最佳实践等多个维度对 synchronizedLock 进行全面深入的解析,并通过大量代码示例帮助你更好地理解它们之间的区别与联系。


📌 一、synchronized 关键字详解

1. 基本概念

synchronized 是 Java 内置的关键字,用于保证多个线程对共享资源访问时的互斥性和可见性。它可以修饰方法或代码块,确保同一时刻只有一个线程可以执行被同步的代码。

2. 使用方式

(1)修饰实例方法
public synchronized void method() {// 同步整个方法体
}

此时锁对象是当前类的实例(即 this)。

(2)修饰静态方法
public static synchronized void staticMethod() {// 同步静态方法
}

此时锁对象是当前类的 Class 对象(即 ClassName.class)。

(3)修饰代码块(推荐)
public void method() {synchronized (this) {// 同步代码块}
}

更灵活,可以指定任意对象作为锁,推荐使用这种方式以减少锁定范围。

3. 特性总结

特性描述
自动释放锁JVM 在同步块执行结束后自动释放锁
不可中断等待获取锁的线程无法被中断
非公平锁多个线程竞争时,不保证先等待的线程优先获得锁
可重入性支持同一个线程多次获取同一把锁

🔑 二、Lock 接口详解(以 ReentrantLock 为例)

1. 基本概念

Lock 是 Java 5 引入的一个接口,位于 java.util.concurrent.locks 包下。常见的实现类有:

  • ReentrantLock:可重入锁
  • ReadWriteLock:读写分离锁(实现类为 ReentrantReadWriteLock

相比 synchronizedLock 更加灵活和强大,提供了更多高级功能。

2. 使用方式

Lock lock = new ReentrantLock();
lock.lock(); // 手动加锁
try {// 临界区逻辑
} finally {lock.unlock(); // 必须放在 finally 块中释放锁
}

⚠️ 注意:必须手动调用 unlock(),否则可能导致死锁!

3. 核心特性

特性描述
手动管理锁需要显式调用 lock()unlock()
可中断等待支持线程在等待锁的过程中响应中断(lockInterruptibly()
超时获取锁支持尝试获取锁并设置超时时间(tryLock(long time, TimeUnit unit)
公平锁/非公平锁构造函数可选择是否启用公平锁
条件变量支持提供 Condition 接口,实现更细粒度的线程通信

🤔 三、synchronizedLock 的核心区别对比表

功能synchronizedLock
加锁方式自动加锁、解锁手动加锁、解锁
锁类型非公平锁可选公平/非公平
可中断❌ 不支持✅ 支持
超时机制❌ 不支持✅ 支持
尝试获取锁❌ 不支持✅ 支持
条件变量❌ 不支持✅ 支持
性能优化JDK 1.6+ 已优化更适合高并发场景
适用场景简单同步需求复杂并发控制场景

🎯 四、使用场景对比与建议

场景推荐使用说明
简单方法或代码块同步synchronized实现简单,无需手动释放锁
高并发、复杂同步控制Lock提供更多控制选项,如公平锁、尝试锁等
需要线程中断响应Locksynchronized 不支持中断等待
需要条件变量配合LockCondition 可替代传统的 wait/notify
需要超时获取锁LocktryLock() 方法非常实用

🧪 五、实战案例分析

案例 1:带超时的锁获取(适用于防止死锁)

Lock lock = new ReentrantLock();boolean isLocked = false;
try {isLocked = lock.tryLock(3, TimeUnit.SECONDS);if (isLocked) {try {// 执行业务逻辑} finally {lock.unlock();}} else {System.out.println("未能在3秒内获取到锁");}
} catch (InterruptedException e) {Thread.currentThread().interrupt();System.out.println("线程被中断");
}

案例 2:使用 Condition 实现生产者-消费者模型

class BoundedQueue {private final Lock lock = new ReentrantLock();private final Condition notFull = lock.newCondition();private final Condition notEmpty = lock.newCondition();private final Queue<Integer> queue = new LinkedList<>();private final int capacity;public BoundedQueue(int capacity) {this.capacity = capacity;}public void put(int value) throws InterruptedException {lock.lock();try {while (queue.size() == capacity) {notFull.await(); // 等待队列不满}queue.add(value);notEmpty.signal(); // 唤醒消费者} finally {lock.unlock();}}public int take() throws InterruptedException {lock.lock();try {while (queue.isEmpty()) {notEmpty.await(); // 等待队列不空}return queue.poll();} finally {lock.unlock();}}
}

🧠 六、底层原理简析(进阶)

1. synchronized 的底层实现

在 JVM 层面,synchronized 是基于 Monitor(监视器)机制实现的。每个 Java 对象都关联一个 Monitor,当线程进入同步块时,会尝试获取该对象的 Monitor,成功则进入,失败则阻塞。

JVM 对其进行了多项优化,包括:

  • 偏向锁(Biased Locking)
  • 轻量级锁(Lightweight Locking)
  • 自旋锁(Spin Lock)
  • 锁粗化(Lock Coarsening)
  • 锁消除(Lock Elimination)

这些优化使得 synchronized 在现代 JVM 上表现优异。

2. ReentrantLock 的底层实现

ReentrantLock 底层依赖于 AbstractQueuedSynchronizer(AQS)框架,是一个基于 CLH(Craig, Landin, and Hagersten)队列的同步工具。

它通过 CAS(Compare and Swap)操作和 volatile 变量实现线程安全,具有更高的可控性和灵活性。


🛠️ 七、最佳实践与注意事项

建议说明
优先考虑 synchronized如果只是简单的同步,优先使用 synchronized,避免复杂代码
Lock 放在 finally 中释放防止因异常导致死锁
使用 tryLock() 防止死锁在某些情况下,尝试获取锁比无限等待更合理
避免嵌套锁容易引发死锁,应尽量避免或使用工具检测
选择公平锁需谨慎公平锁虽然保证顺序,但可能带来性能损耗
使用 Condition 替代 wait/notify更清晰、线程安全

📘 八、总结

项目synchronizedLock
是否内置✅ 是❌ 否
使用难度简单复杂
控制粒度
功能丰富度一般强大
性能表现更好(高并发)
推荐用途初学者、简单同步高级用户、复杂并发控制

在实际开发中,两者各有优势,选择哪一个取决于具体的应用场景和团队技术栈。对于大多数中小型项目,synchronized 已经足够;而在需要更高并发控制能力的场景下,Lock 更具优势。


🎯 点赞、收藏、转发本文,让更多开发者受益!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/bicheng/84818.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Notepad++如何列选

在 Notepad 中&#xff0c;你可以通过 列模式&#xff08;Column Mode&#xff09; 进行垂直选择文本&#xff08;列选&#xff09;&#xff0c;以下是具体操作方法&#xff1a; 方法 1&#xff1a;键盘 鼠标列选 按住 Alt 键&#xff08;或 Alt Shift&#xff09;。 按住鼠…

华为OD机考-水仙花数Ⅰ-逻辑分析(JAVA 2025B卷)

import java.util.*; public static Integer get(int count,int c){if(count<3||count>7){return -1;}//存储每位数的最高位……最低位int[] arr new int[count];List<Integer> res new ArrayList<>();for(int i(int) Math.pow(10,count-1);i<(int) Math…

基于 STL+VMD 二次分解的 Informer-LSTM 并行预测模型详解与案例

一、背景与动机 在时间序列预测中,如电力负荷、风速、交通流量等复杂数据常表现为: 非线性:趋势+季节+突变+噪声 多尺度:高频扰动与低频变化共存 长时依赖:远期信息也影响当前预测 传统模型(如 ARIMA、LSTM)往往无法兼顾全局趋势建模与局部扰动感知,因此我们提出一种 …

【Linux Learning】SSH连线出现警告:WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!

问题&#xff1a;WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY! Someone could be eavesdropping on you right now (man-in-the-middle attack)! It is al…

轻量级密码算法PRESENT的C语言实现(无第三方库)

一、PRESENT算法介绍 PRESENT是一种超轻量级分组密码算法&#xff0c;由Bogdanov等人在2007年提出&#xff0c;专门为资源受限环境如RFID标签和传感器网络设计。该算法在硬件实现上仅需1570个门等效电路(GE)&#xff0c;在保持较高安全性的同时实现了极小的硬件占用空间。PRES…

if的简化书写,提高执行效率

很多时候可能有下面判断 if(a0) {b1;} else if(a1) {b0;} 就是ba的反向值&#xff1a; a0;b1&#xff1b; a1;b0; 这时&#xff0c;可以简化如下&#xff1a; ba^1 使用异或&#xff0c;程序更简洁&#xff0c;执行效率也更高 其他的也可以类似使用按位异或优化代码

Vim 调用外部命令学习笔记

Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…

bash挖矿木马事件全景复盘与企业级防御实战20250612

&#x1f427; CentOS “-bash 挖矿木马” 事件全景复盘与企业级防御实战 ✍️ 作者&#xff1a;Narutolxy | &#x1f4c5; 日期&#xff1a;2025-06-12 | &#x1f3f7;️ 标签&#xff1a;Linux 安全、应急响应、运维加固、实战复盘 &#x1f4d8; 内容简介 本文是一场真实…

「Linux中Shell命令」Shell命令基础

知识点详细解析 Shell简介 Shell是Linux操作系统系统中用户与操作系统内核交互的接口。它既是命令解释器,负责接收用户输入的命令并将其转换为内核能够理解的指令,也是一种脚本编程语言。作为Linux操作系统的重要组成部分,Shell扮演着用户与系统内核之间的"中间人"…

202557读书笔记|《梦里花落知多少(轻经典)》——有你在的地方才最美

《梦里花落知多少&#xff08;轻经典&#xff09;》作者三毛&#xff0c;物极必反&#xff0c;阴晴圆缺&#xff0c;小满即万全么&#xff1f;因为幸福过于满溢。所以幸福被收走了。 没有看过太多三毛的作品&#xff0c;给我的感觉她是很敏感&#xff0c;多愁善感及没有安全感…

对象映射 C# 中 Mapster 和 AutoMapper 的比较

Mapster和AutoMapper是C#领域两大主流对象映射库&#xff0c;各具特色。Mapster以高性能著称&#xff0c;使用表达式树实现零反射映射&#xff0c;首次编译后执行效率极高&#xff0c;适合对性能敏感的场景&#xff1b;AutoMapper则提供更丰富的功能集&#xff0c;如条件映射和…

QEMU源码全解析 —— 块设备虚拟化(26)

接前一篇文章:QEMU源码全解析 —— 块设备虚拟化(25) 本文内容参考: 《趣谈Linux操作系统》 —— 刘超,极客时间 《QEMU/KVM源码解析与应用》 —— 李强,机械工业出版社 Virt

微软PowerBI考试 PL300-选择 Power BI 模型框架【附练习数据】

微软PowerBI考试 PL300-选择 Power BI 模型框架 20 多年来&#xff0c;Microsoft 持续对企业商业智能 (BI) 进行大量投资。 Azure Analysis Services (AAS) 和 SQL Server Analysis Services (SSAS) 基于无数企业使用的成熟的 BI 数据建模技术。 同样的技术也是 Power BI 数据…

RED DA认证-EN18031网络安全常见问题以及解答

Q&#xff1a;RED DA是否对所有无线模块和设备强制要求&#xff1f; A&#xff1a;是的&#xff0c;RED DA适用于欧盟境内销售的所有无线设备&#xff0c;包括WWAN、蓝牙或Wi-Fi模块。唯一例外是GNSS模块&#xff08;仅支持接收功能&#xff0c;无需认证&#xff09;。 Q&…

腾讯开源 ovCompose 跨平台框架:实现一次跨三端(Android/iOS/鸿蒙)

在移动应用开发领域&#xff0c;跨平台技术一直是开发者们追求的目标&#xff0c;它能够帮助企业降低开发成本、提高开发效率&#xff0c;同时保证应用在不同平台上的一致性体验。2025 年 6 月 3 日&#xff0c;腾讯视频团队迎来了一个重要的里程碑 —— 正式发布 ovCompose 跨…

对3D对象进行形变分析

1&#xff0c;目的 分析3D实例对象相对标准参照物的形变。 一般用于质地较软的材质&#xff08;例如橡胶&#xff0c;布料&#xff09;查找&#xff0c;检查等。 标准参考模型 需匹配的实例&#xff1a; 形变后的模型&#xff1a;* 形变后的模型&#xff1a; 实例形变后的…

宝塔面板WordPress中使用Contact Form 7插件收不到邮件的解决方法

如果是宝塔面板的环境下&#xff0c;在WordPress中使用Contact Form 7插件提交表单时显示成功&#xff0c;但邮箱未收到邮件&#xff0c;可能是由于服务器邮件功能配置问题。以下是几种常见解决方法&#xff1a; 1. 检查邮件发送方式 默认情况下&#xff0c;Contact Form 7 使…

Android中的DX、D8、R8

Kotlin 版本所需的 AGP、D8 和 R8 版本 :https://developer.android.google.cn/build/kotlin-support?hlzh_cn R8&#xff1a;https://developer.android.google.cn/tools/retrace?hlzh_cn D8&#xff1a;https://developer.android.google.cn/tools/d8?hlzh_cn 如上图&…

通义灵码 AI IDE 上线!智能体+MCP 从手动调用工具过渡到“AI 主动调度资源”

告诉大家一个好消息&#xff0c;通义灵码发布了 AI 编程 IDE &#xff1a;Lingma IDE &#xff0c;你没看错&#xff0c;通义灵码也推出了自己的 AI IDE 客户端&#xff0c;不是 AI 编程插件&#xff0c;是 IDE 。 Lingma IDE 是基于 VS Code 开源版本构建的智能代码编辑器&am…

快速解决软件测试的逻辑方法运用

在软件测试过程中&#xff0c;遇到复杂问题时&#xff0c;如何快速定位和解决&#xff1f;关键在于运用逻辑方法&#xff0c;系统化地分析问题、设计测试用例、优化测试流程。本文将介绍几种高效的逻辑方法&#xff0c;帮助测试工程师提升效率&#xff0c;减少盲测和重复劳动。…