news 2026/4/12 16:52:38

Java 锁机制全面解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java 锁机制全面解析

今天我们来聊聊Java中的锁机制

一、为什么需要锁

在单线程程序中,所有代码按顺序执行,不会出现资源竞争的问题;但在多线程并发场景下,多个线程同时访问共享资源(如全局变量、数据库连接、文件等)时,会出现竞态条件,导致数据不一致。锁是解决多线程并发访问共享资源的工具,本质是给共享资源加独占权限,保证多线程对共享资源的互斥访问,解决线程安全问题。

二、Java中常见的锁实现

Synchronized

这是 Java 提供的原生关键字。它像是一个全自动洗衣机,你只需要把衣服丢进去(加上关键字),剩下的 JVM 帮你搞定。

特点:

  • 隐式锁:自动加锁/解锁,无需手动释放,即使抛异常也会释放;
  • 可重入、非公平锁;
  • JDK 1.6 后支持锁升级(偏向→轻量→重量);
  • 独占锁(悲观锁)。
public class SynchronizedUsage { // 1. 修饰实例方法:锁是当前对象(this) public synchronized void instanceMethod() {} // 2. 修饰静态方法:锁是当前类的Class对象 public static synchronized void staticMethod() {} // 3. 修饰代码块:锁是指定的对象(灵活) public void codeBlock() { // 锁对象可以是this、Class对象、自定义对象 synchronized (SynchronizedUsage.class) { // 临界区代码 } } }

ReentrantLock

它是java.util.concurrent.locks包下的一个类。它像是一个手动档汽车,更灵活,但也更考验车技。

特点:

  • 显式锁:需手动 lock()、unlock();
  • 可重入、可指定公平 / 非公平(默认非公平);
  • 支持可中断锁、超时获取锁;
  • 支持条件变量,可实现精准唤醒线程;
  • 独占锁(悲观锁)。
Lock lock = new ReentrantLock(); lock.lock(); // 手动加锁 try { // 临界区代码 } finally { lock.unlock(); // 必须在 finally 里手动释放,否则会造成死锁 }

三、锁的分类

Java 中的锁可以从多个维度分类,这些分类并非互斥,而是从不同视角描述锁的特性。

1. 按获取锁的顺序:公平锁 vs 非公平锁

  • 公平锁:多个线程按照申请锁的顺序来获取锁,缺点是频繁的队列切换会带来性能损耗;
  • 非公平锁:线程获取锁时尝试直接抢占,抢锁失败再进入等待队列,性能较高,缺点是可能导致部分线程长期等待。但性能收益远大于弊端。

2. 按对待并发的态度:乐观锁 vs 悲观锁

这是一种设计思想,并非具体的锁实现。

  • 悲观锁:总是假设最坏的情况,认为共享资源访问每次都会有冲突发生,所以先加锁再访问资源。适用写操作多、冲突率高的情况。
  • 乐观锁:认为冲突很少发生,先访问资源,只是在提交时检查是否有冲突。适用读操作多、冲突率低的情况。

3. 按资源访问方式:独享锁 vs 共享锁

  • 独享锁:同一时间,只有一个线程能持有该锁。
  • 共享锁:同一时间,允许多个线程持有该锁。

4. 按是否可重复获取:可重入锁

  • 可重入锁:当一个线程已经持有某个锁时,再次请求获取该锁时不会被自己阻塞,而是直接获取(锁的计数器+1)。可以避免锁嵌套导致的死锁。

5. 按锁的量级:偏向锁 → 轻量级锁 → 重量级锁

这是 synchronized 的锁升级机制,JVM 为了提升锁性能,根据线程竞争的程度来动态调整适应,锁的升级是不可逆的。

  • 偏向锁:一段同步代码一直被一个线程所访问,那么该线程会自动获取锁;
  • 轻量级锁:当有第二个线程尝试获取偏向锁时,偏向锁会升级成轻量级锁,其他的线程会通过自旋的形式尝试获取锁;
  • 重量级锁:当锁为轻量级锁时,另一个线程自旋次数到达上限后还没有获取到锁,就会升级成重量级锁,其他申请的线程会进入阻塞。

6. 自旋锁 & 自适应自旋

自旋锁

当线程获取锁失败时,不立即阻塞挂起,而是循环重试(自旋)一段时间,看是否能获取到锁。

  • 优点:避免线程内核态 / 用户态切换的开销;
  • 缺点:自旋消耗 CPU 资源,若锁持有时间长,自旋会浪费 CPU。

自适应自旋

JDK 1.6 后引入,自旋次数不再固定,而是根据「前一次自旋的结果」「锁持有者的状态」动态调整:

  • 若前一次自旋成功获取锁,本次自旋次数增加;
  • 若前一次自旋失败,本次自旋次数减少甚至直接放弃自旋。

7. 锁优化:锁粗化 & 锁清除

这是 JVM 的自动优化手段,无需开发者手动操作。

  • 锁粗化:JVM将多个连续的加锁 / 解锁操作(如循环内的同步代码)扩展到整个操作序列的外部(循环外)合并为一次;
  • 锁清除:JVM通过分析,检测到某个同步锁保护的资源没有被多线程共享,则自动移除该锁。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/12 13:57:13

Java HashMap全面解析

HashMap 是 Java 集合框架中最常用的键值对(Key-Value)存储容器;同时在安卓开发中,HashMap 是本地数据存储、临时缓存的核心工具。接下来我们来看看 HashMap 的定义、底层结构、核心算法、扩容机制、线程安全问题。一、HashMap定义…

作者头像 李华
网站建设 2026/4/11 9:08:53

ChatGPT写论文指令:从技术原理到高效实践指南

ChatGPT写论文指令:从技术原理到高效实践指南 “请帮我写一篇关于的综述。”——把这句话丢给 ChatGPT,十分钟后你会得到一篇看似流畅却漏洞百出的“学术散文”。Nature 2023 年对 1,600 名研究生做的问卷里,73% 的人承认“AI 输出经常跑题”…

作者头像 李华
网站建设 2026/3/27 16:45:02

Conda下载WebRTC失败问题全解析:从依赖冲突到稳定安装指南

Conda下载WebRTC失败问题全解析:从依赖冲突到稳定安装指南 摘要:本文针对开发者使用conda安装WebRTC时常见的依赖冲突、网络超时和版本不匹配问题,提供系统性的解决方案。通过分析conda与WebRTC的依赖树结构,给出三种可靠安装方案…

作者头像 李华
网站建设 2026/4/2 18:21:43

从零到英雄:如何用STM32打造你的第一辆智能避障小车

从零到英雄:如何用STM32打造你的第一辆智能避障小车 1. 项目概述与核心设计思路 第一次看到智能小车在桌面上灵活地避开障碍物时,我被这种将代码转化为物理运动的魔力深深吸引。作为嵌入式开发的经典练手项目,基于STM32的智能避障小车完美融合…

作者头像 李华
网站建设 2026/4/11 11:48:31

ESP32开发环境全攻略:VSCode与PlatformIO的完美结合

1. 为什么选择VSCodePlatformIO开发ESP32? 如果你正在寻找一个高效、现代化的ESP32开发环境,VSCode和PlatformIO的组合绝对是你的不二之选。相比传统的Arduino IDE,这个组合提供了更强大的代码补全、智能提示、版本控制集成等功能&#xff0…

作者头像 李华