news 2026/2/17 6:00:55

Java锁机制

作者头像

张小明

前端开发工程师

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

概述

  1. 按实现层面划分
    • [内置锁]:synchronized是JVM层面实现的,无需手动释放锁,属于内置锁。
    • [显式锁]:ReentrantLock为代表的显式锁,需要手动释放锁,功能更加灵活,位于java.util.concurrent.locks包,Java代码层面实现。
  2. 按锁的竞争机制划分
    • [悲观锁]:synchronizedReentrantLock都为悲观锁,每次操作资源都会加锁,阻塞其他线程。
    • [乐观锁]:不加锁直接操作,通过CAS验证操作是否成功,失败则重试,例如AtomicInteger
  3. 按锁的可重入性划分
    • [可重入锁]:对于已获取到锁的线程可再次获取同一把锁(避免自身死锁),synchronizedReentrantLock均为可重入锁。
    • [不可重入锁]:持有锁的线程无法再次获取这把锁,容易引起自身死锁。
  4. 锁的升级
    • 偏向锁 -> 轻量级锁 -> 重量级锁(JDK1.6优化后,synchronized会根据竞争激烈程度自动升级,逐步提升并发性能)

具体

一、synchronized

1. 用法

public class SynchronizedDemo { // 1. 修饰实例方法:锁的是「当前类的实例对象」(this) public synchronized void instanceMethod() { // 线程安全的实例方法逻辑 System.out.println("修饰实例方法,锁:" + this); } // 2. 修饰静态方法:锁的是「当前类的 Class 对象」(SynchronizedDemo.class) public static synchronized void staticMethod() { // 线程安全的静态方法逻辑 System.out.println("修饰静态方法,锁:" + SynchronizedDemo.class); } // 3. 修饰同步代码块:锁的是「括号内指定的对象」(灵活可控) public void codeBlockMethod() { // 可选锁对象:this(实例对象)、Class 对象、自定义任意对象 Object lock = new Object(); synchronized (lock) { // 线程安全的代码块逻辑 System.out.println("修饰代码块,锁:" + lock); } } }

synchronized竞争的是一个资源对象,无论是修饰的实例方法、静态方法还是代码块,只是对象的类型不同而已。(可以是方法当前类的实例对象、class对象、自定义的任意对象)

2. 实现原理

依赖于「Java对象头」和「监视器锁」,不同JDK版本略有差异

  • JDK1.6之前:仅支持「重量级锁」,依赖操作系统的「互斥量(Mutex)」实现,线程竞争时会触发「用户态 <-> 内核态」的上下文切换,开销极大,性能较差。
  • JDK1.6之后:引入了「锁升级」机制(偏向锁 -> 轻量级锁 -> 重量级锁),根据竞争激烈程度逐步升级,大幅优化性能:
    1. 偏向锁:无多线程竞争时,锁偏向第一个获取锁的线程,后续该线程再次获取锁时,无需任何竞争操作,直接获取锁(开销极低)。
    2. 轻量级锁:出现少量线程竞争时,偏向锁升级为轻量级锁,通过「CAS 操作」实现锁的获取与释放,无需阻塞线程,仅存在少量自旋开销。
    3. 重量级锁:出现大量线程竞争时,轻量级锁升级为重量级锁,依赖操作系统互斥量实现,竞争失败的线程会被阻塞挂起,避免空耗 CPU,此时开销最大,但能保证高并发场景下的稳定性。
    4. ⭐锁升级是单向的,无法降级。
3. 核心特性
  • 可重入性:线程持有锁后,可再次获取同一把锁(如同步方法中调用另一同步方法),避免自身死锁。
  • 隐式释放锁:无需手动调用释放方法,同步代码块 / 方法执行完毕、抛出异常时,JVM 会自动释放锁,降低资源泄露风险。
  • 非公平锁:默认采用非公平锁策略(线程获取锁时,不遵守先到先得的顺序,可能存在插队现象),吞吐量更高(公平锁会带来额外的排队开销)。

二、ReentrantLock

1. 用法

import java.util.concurrent.locks.ReentrantLock; public class ReentrantLockDemo { // 1. 创建 ReentrantLock 实例(默认非公平锁,传入 true 为公平锁) private static final ReentrantLock lock = new ReentrantLock(false); public void doTask() { // 2. 获取锁(lock() 方法,阻塞式获取) lock.lock(); try { // 3. 执行线程安全的业务逻辑 System.out.println(Thread.currentThread().getName() + " 已获取锁,执行任务"); } finally { // 4. 释放锁(必须在 finally 中,保证无论是否异常,都能释放锁) lock.unlock(); System.out.println(Thread.currentThread().getName() + " 已释放锁"); } } public static void main(String[] args) { ReentrantLockDemo demo = new ReentrantLockDemo(); // 启动 2 个线程竞争锁 new Thread(demo::doTask, "线程1").start(); new Thread(demo::doTask, "线程2").start(); } }

finally释放锁是必须的,防止try抛出异常,锁无法释放,会导致其他线程永久阻塞,引发死锁。

2. 核心功能扩展

ReentrantLock提供了synchronized不具备的高级功能:

  • 支持公平锁/非公平锁:创建实例的时候可以设置采用公平锁还是非公平锁,默认非公平锁(false)
  • 支持获取锁超时:通过trylock(long timeout, TimeUnit unit)方法,设置锁获取超时时间,超时后自动放弃获取锁,返回false,避免长时间阻塞。
  • 支持可中断获取锁:通过lockInterruptibly()方法,获取锁的线程可被其他线程中断(调用thread.interrupt()),中断后抛出InterruptedException,并释放锁,灵活控制线程状态。
  • 提供锁状态查询:如isLocked()(判断锁是否被持有)、isHeldByCurrentThread()(判断当前线程是否持有该锁)、getHoldCount()(获取当前线程持有该锁的次数),方便监控和调试。
3. 原理

ReentrantLock的底层基于AQS(AbstractQueuedSynchronizer,抽象队列同步器)实现,AQS 是 JUC 包中所有显式锁、同步工具类的核心框架。 核心逻辑:

  1. AQS 内部维护一个「volatile 状态变量state」和一个「双向链表同步队列」。
  2. state用于标记锁的状态:state=0表示锁未被持有,state>0表示锁被持有(state的值等于线程持有锁的次数,体现可重入性)。
  3. 线程获取锁时,通过 CAS 操作修改state:若state=0,则将state改为 1,获取成功;若state>0且是当前线程持有,则state加 1(可重入),否则加入同步队列阻塞等待。
  4. 线程释放锁时,将state减 1,当state=0时,释放锁并唤醒同步队列中的下一个线程。
4. 核心特性
  1. 可重入性:和synchronized一样,支持线程重复获取同一把锁,通过state变量计数实现。
  2. 显式释放锁:必须手动调用unlock()释放,依赖开发者规范,灵活性高但风险也高(容易遗漏释放)。
  3. 功能灵活:支持公平锁、超时获取、可中断等高级功能,适配复杂并发场景。
  4. 性能优异:在高并发场景下,性能略优于synchronized(JDK 1.6 后synchronized优化,两者性能差距不大)。

三、synchronized锁升级

锁的载体 --Java对象头synchronized锁的是「对象」,而锁状态的信息,就存储在Java 对象头(Object Header)中(仅针对普通对象,数组对象的对象头额外包含数组长度)。 Java 对象头在 32 位 JVM 和 64 位 JVM 中长度分别为 8 字节和 16 字节,核心包含两部分(以 64 位 JVM 为例):

  1. Mark Word(标记字段,8字节):存储对象的锁状态、哈希码、GC年龄、偏向线程ID等核心信息,是锁升级的「核心载体」。
  2. Klass Pointer(类型指针,8字节):指向对象所属类的Class对象,用于确定对象的类型。
锁状态Mark Word 核心字段(64 位)
无锁哈希码(25 位)+ GC 年龄(4 位)+ 无锁标记(1 位)
偏向锁偏向线程 ID(54 位)+ 偏向时间戳(2 位)+ GC 年龄(4 位)+ 偏向锁标记(1 位)
轻量级锁指向栈中锁记录的指针(63 位)+ 轻量级锁标记(1 位)
重量级锁指向监视器锁(Monitor)的指针(63 位)+ 重量级锁标记(1 位)
第一步:无锁 -> 偏向锁(无竞争场景)
  1. 第一个线程获取锁时,JVM 通过 CAS 操作,将Mark Word中的「偏向线程 ID」设置为当前线程的 ID,同时将「锁标记位」改为「偏向锁标记」。
  2. 该线程后续再次获取该对象的锁时,无需再执行 CAS 操作或阻塞,只需简单检查Mark Word中的:
    • 偏向线程 ID 是否为当前线程 ID;
    • 偏向锁标记是否有效。
  3. 若两者都满足,直接获取锁成功(「偏向」的含义就是锁会「偏爱」这个线程),全程无额外开销,效率极高。
第二步:偏向锁 → 轻量级锁(少量线程竞争,无阻塞)
  1. 加锁流程
  • 线程获取锁时,先在自己的栈帧中创建一个「锁记录(Lock Record)」,用于存储对象Mark Word的副本(称为「Displaced Mark Word」)。
  • 线程通过 CAS 操作,将对象Mark Word中的内容替换为「指向当前线程栈中锁记录的指针」。
  • 若 CAS 成功,说明锁获取成功,将Mark Word的锁标记位改为「轻量级锁标记」,线程继续执行同步代码。
  • 若 CAS 失败,说明有其他线程正在竞争该锁,当前线程不会被阻塞,而是进入「自旋」(反复执行 CAS 操作,尝试获取锁)。
  1. 解锁流程
  • 线程执行完同步代码后,通过 CAS 操作,将对象Mark Word中的「锁记录指针」替换回原来的「Displaced Mark Word」(栈中锁记录存储的副本)。
  • 若 CAS 成功,说明无其他线程竞争,解锁成功,锁状态回到无锁。
  • 若 CAS 失败,说明有其他线程在自旋竞争,此时会将轻量级锁升级为重量级锁,同时唤醒自旋的线程。
第三步:轻量级锁 → 重量级锁(大量线程竞争,阻塞式竞争)
  1. 加锁流程
  • 锁升级为重量级锁后,对象Mark Word中会存储「指向 Monitor 的指针」,Monitor 是一个用于管理锁竞争的核心数据结构。
  • 线程获取锁时,会尝试获取 Monitor 的「持有权」(Monitor 中的owner字段记录持有锁的线程)。
  • 若获取成功,owner字段设置为当前线程,线程执行同步代码。
  • 若获取失败,当前线程会被加入 Monitor 的「阻塞队列」,被操作系统挂起(从用户态切换到内核态),放弃 CPU 执行权,直到被唤醒。
  1. 解锁流程
  • 线程执行完同步代码后,释放 Monitor 的持有权(将owner字段置为 null)。
  • 唤醒阻塞队列中的一个线程(通过操作系统的唤醒机制),让其尝试获取锁。
  • 锁状态保持为重量级锁,不会降级(单向升级)。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/8 20:30:47

计算机毕业设计springboot文档查重系统 完善诚信建设系统文档以满足检查要求基于SpringBoot的毕业论文相似度检测平台 基于SpringBoot的学术文献原创性审核系统

计算机毕业设计springboot文档查重系统vhg01b87 &#xff08;配套有源码 程序 mysql数据库 论文&#xff09; 本套源码可以在文本联xi,先看具体系统功能演示视频领取&#xff0c;可分享源码参考。 在数字化时代&#xff0c;文档的编写和传播变得前所未有地便捷&#xff0c;这也…

作者头像 李华
网站建设 2026/2/16 9:30:24

基于SpringBoot的勤工俭学系统设计与实现

文章目录 详细视频演示项目介绍技术介绍功能介绍核心代码系统效果图源码获取 详细视频演示 文章底部名片&#xff0c;获取项目的完整演示视频&#xff0c;免费解答技术疑问 项目介绍 勤工俭学是高校资助体系的重要组成部分&#xff0c;旨在帮助学生通过劳动获得经济补助&…

作者头像 李华
网站建设 2026/2/17 1:39:03

‌AI生成的测试用例如何做“同行评审”?

‌一、背景&#xff1a;为什么AI生成的测试用例必须经过同行评审&#xff1f;‌ AI驱动的测试用例生成工具&#xff08;如APITestGenie、Testim AI、Selenium AI&#xff09;已在主流互联网企业落地&#xff0c;平均可将用例编写效率提升60%以上。然而&#xff0c;AI生成的用例…

作者头像 李华
网站建设 2026/2/17 2:19:32

计算机毕业设计springboot大学生在校实习信息管理系统 基于SpringBoot的高校学生实习过程管理平台 面向校企协同的SpringBoot实习事务一体化系统

计算机毕业设计springboot大学生在校实习信息管理系统c126e&#xff08;配套有源码 程序 mysql数据库 论文&#xff09; 本套源码可以在文本联xi,先看具体系统功能演示视频领取&#xff0c;可分享源码参考。高校扩招与产教融合的双轮驱动下&#xff0c;实习已从“教学环节”升级…

作者头像 李华
网站建设 2026/2/16 23:20:27

我把AI生成的用例和代码覆盖率绑定,自动补全

引言&#xff1a;覆盖率困局与AI破局之道 在敏捷开发持续迭代的压力下&#xff0c;测试团队面临两大核心矛盾&#xff1a;用例覆盖盲区难以根除&#xff08;如边界条件遗漏率达38%&#xff09;&#xff0c;以及覆盖率优化严重滞后于代码变更。传统人工维护测试集的方式&#x…

作者头像 李华