当前位置:首页 > Java

java锁是如何实现的

2026-03-03 15:21:10Java

Java锁的实现机制

Java中的锁机制主要通过synchronized关键字和java.util.concurrent.locks包下的显式锁(如ReentrantLock)实现。以下是两种锁的核心实现原理:

synchronized的实现

synchronized基于JVM内置的监视器锁(Monitor)实现,依赖对象头中的Mark Word和线程栈帧中的锁记录(Lock Record)。

对象头结构
32位JVM的Mark Word布局(以偏向锁为例):

java锁是如何实现的

|-------------------------------------------------------|--------------------|
|                  Mark Word (32 bits)                   |       State        |
|-------------------------------------------------------|--------------------|
| hashcode:25 | age:4 | biased_lock:1 | lock:2 (01)      |       Normal       |
| thread:23 | epoch:2 | age:4 | biased_lock:1 | lock:2 (01)|      Biased       |
| ptr_to_lock_record:30                         | lock:2 (00)| Lightweight Locked |
| ptr_to_heavyweight_monitor:30                 | lock:2 (10)| Heavyweight Locked |
|                                              | lock:2 (11)|    Marked for GC   |
|-------------------------------------------------------|--------------------|

锁升级过程

  1. 无锁状态:初始状态,对象未被任何线程锁定。
  2. 偏向锁:通过CAS设置Mark Word中的线程ID,适用于单线程重复访问场景。
  3. 轻量级锁:当多线程竞争时,撤销偏向锁,线程通过CAS将Mark Word替换为指向栈中锁记录的指针。
  4. 重量级锁:竞争加剧时,轻量级锁升级为重量级锁,未获取锁的线程进入阻塞状态,依赖操作系统的互斥量(Mutex)。

ReentrantLock的实现

ReentrantLock基于AQS(AbstractQueuedSynchronizer)实现,核心通过CAS操作和CLH队列管理线程阻塞与唤醒。

java锁是如何实现的

AQS核心结构

  • state字段:表示锁的重入次数(如0表示未锁定,≥1表示被持有)。
  • CLH队列:双向链表结构的等待队列,节点保存阻塞线程信息。

加锁流程(非公平锁为例)

final void lock() {
    if (compareAndSetState(0, 1)) // CAS尝试直接获取锁
        setExclusiveOwnerThread(Thread.currentThread());
    else
        acquire(1); // 进入AQS排队逻辑
}

AQS的acquire方法

  1. 尝试通过tryAcquire获取锁(子类实现,如检查state是否为0)。
  2. 失败后将线程封装为Node加入队列尾部,通过LockSupport.park阻塞线程。
  3. 前驱节点释放锁时,唤醒后续节点重新竞争。

锁的对比

特性 synchronized ReentrantLock
实现层级 JVM内置 JDK代码层面
公平性 非公平 支持公平/非公平(构造函数指定)
中断响应 不支持 支持lockInterruptibly
条件变量 单一wait/notify 支持多个Condition
锁释放 自动(代码块结束) 需手动unlock

性能优化建议

  • 偏向锁:适用于单线程占优场景,可通过JVM参数-XX:+UseBiasedLocking启用(JDK 15后默认禁用)。
  • 自旋优化:重量级锁竞争时,线程会自旋尝试获取锁(通过-XX:PreBlockSpin调整自旋次数)。
  • 锁消除:JIT编译器对不可能存在竞争的锁进行消除(如局部对象锁)。
  • 锁粗化:将相邻的同步块合并减少锁开销。

通过合理选择锁类型和优化参数,可以平衡线程安全与性能需求。

分享给朋友:

相关文章

vue如何实现重新实现主题

vue如何实现重新实现主题

Vue 主题切换的实现方法 使用 CSS 变量动态切换主题 定义主题相关的 CSS 变量,通过修改这些变量实现主题切换。在根元素(如 :root)中定义默认主题的变量,在特定类名下定义其他主题的变量。…

java如何调用接口

java如何调用接口

调用接口的基本方法 在Java中调用接口通常涉及实现接口或使用接口引用对象。以下是几种常见场景的示例: 定义接口 public interface MyInterface { void d…

如何运行java文件

如何运行java文件

运行Java文件的方法 确保已安装Java Development Kit (JDK),可通过命令行输入java -version和javac -version验证安装。 编写Java代码并保存为.…

java如何输入数组

java如何输入数组

输入数组的方法 在Java中,可以通过多种方式输入数组,具体取决于输入源(如控制台、文件等)和数组类型(如基本类型或对象类型)。以下是几种常见的方法: 使用Scanner从控制台输入 对于基本数据类…

如何学好java

如何学好java

理解基础概念 掌握Java的核心概念是学习的基础。包括数据类型、变量、运算符、控制流(如循环和条件语句)、数组等。理解面向对象编程(OOP)的四大特性:封装、继承、多态和抽象。 实践编程练习 通过实…

java如何实现多线程

java如何实现多线程

实现多线程的方法 在Java中,实现多线程主要有两种方式:继承Thread类和实现Runnable接口。此外,还可以使用ExecutorService等高级工具类来管理线程。 继承Thread类 通…