JAVA并发编程ReentrantLock核心原理剖析

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: 本文介绍了Java并发编程中ReentrantLock的重要性和优势,详细解析了其原理及源码实现。ReentrantLock作为一种可重入锁,弥补了synchronized的不足,如支持公平锁与非公平锁、响应中断等。文章通过源码分析,展示了ReentrantLock如何基于AQS实现公平锁和非公平锁,并解释了两者的具体实现过程。

JAVA并发编程系列以及陆续出了5篇,第六篇的主角ReentrantLock该出场了。之前《一文看懂全部锁机制》谈到可重入锁、《JAVA并发编程AQS原理剖析》谈到了JUC灵魂AQS,那么AQS的思想优秀实践者ReentrantLock是怎么实现AQS的呢?

1、ReentrantLock是什么,有哪些优点

    ReentrantLock英文翻译以及顾名思义:可重入锁。之前文章说过,还有synchronized也是可重入锁。竟然JDK最开始有了synchronized这个可重入锁,而且JDK1.6之后也对synchronized进行锁优化,性能堪比JUC里的其他Lock()。为什么还提供了ReentrantLock呢?在《JAVA并发编程volatile核心原理》文中开头我们就简单的列了synchronized的几个缺点,包括:阻塞时间过长,不可中断、是非公平锁。

所以,同样是可重入锁,ReentrantLock必须有一些亮点。它的优点就是较好的补足synchronized的缺点,提供了非常灵活多变的特性,满足系统项目研发的需求。


     优点有:

     1、支持公平锁+非公平锁。(synchronized仅支持非公平锁)

     2、支持响应中断、超时。(synchronized不支持超时)

     3、支持线程尝试获取锁。(synchronized不支持)


2、具体说说ReentrantLock的原理,看过ReentrantLock源码吗


    话说到这份上,好像不看源码不行了。上源码,不要慌,它的核心源码就这几行,先扫一眼:


刚面试官问:具体说说它的原理?


少废话,一句话总结它的原理:ReentrantLock是AQS的具体实现,实现了公平锁和不公平锁。ReentrantLock源码里有三个内部类。


一个是Sync抽象类;sync 继承了AQS 队列同步器。所以ReentrantLock是AQS的实现。

一个是FailSync类,实现了Sync类,实现的是公平锁。

一个是NonFairSync类,也是实现Sync类,实现的是非公平锁。


“好家伙,总结的还不错”面试官心嘀咕着,继续问:


2.1 公平锁是怎么实现的?

    我们直接看源码,公平锁的lock加锁是acquire(1)方法。

接下来源码是,就看到这里就很清晰了。

public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }


首先,公平锁加锁可能有三部逻辑执行。

第一步:tryAcquire(1),尝试去获取锁。如果成功了,就没有后面两个步骤的事。

第二步:如果第一步获取失败,把当前线程封装为独占锁类型NODE 进入AQS 的FIFO 队列,等待被按顺序唤醒。

第三步:第二步执行后,也会调用selfInterrupt(),里面的源码就是线程自我中断,修改中断标识位为:true。



那具体再说说第一步tryAcquire(1),是如何获取线程锁的?(候选人内心有点破防:面试官问题咋那么多...)


具体就是:

1、先判断当前AQS队列的state是否为0,如果是0,说明现在可以竞争锁。

2、接下来继续判断AQS的同步队列,如果队列是空、或者队列不为空且队列里的节点是不是自己,就去竞争锁。

3、如果竞争锁成功,通过CAS去设置AQS的state值为1,并帮AQS的当前占有锁的NODE 引用线程改完自己。


源码如下:

2.2 非公平锁又是怎么实现的?

   new ReentrantLock()默认的就是非公平锁。

public ReentrantLock() {
        sync = new NonfairSync();
    }


非公平锁的竞争锁就比较暴力,上来就直接通过CAS去竞争,

如果获取失败,进入acquire(1),继续去尝试获取锁。

这里和公平锁也是不一样,它没有判断队列情况,继续用CAS方式去看能否修改state获取锁。


如果竞争失败,就会进入AQS队列,等待被唤醒....

今天暂时分享到这,其实可重入锁里面的源码还有很多内容,篇幅有限,等源码专区出来再全部分享。

相关文章
|
6天前
|
SQL Java 数据库
2025 年 Java 从零基础小白到编程高手的详细学习路线攻略
2025年Java学习路线涵盖基础语法、面向对象、数据库、JavaWeb、Spring全家桶、分布式、云原生与高并发技术,结合实战项目与源码分析,助力零基础学员系统掌握Java开发技能,从入门到精通,全面提升竞争力,顺利进阶编程高手。
144 1
|
1月前
|
安全 Java 数据库连接
2025 年最新 Java 学习路线图含实操指南助你高效入门 Java 编程掌握核心技能
2025年最新Java学习路线图,涵盖基础环境搭建、核心特性(如密封类、虚拟线程)、模块化开发、响应式编程、主流框架(Spring Boot 3、Spring Security 6)、数据库操作(JPA + Hibernate 6)及微服务实战,助你掌握企业级开发技能。
246 3
|
7天前
|
Java 开发者
Java并发编程:CountDownLatch实战解析
Java并发编程:CountDownLatch实战解析
238 100
|
23天前
|
算法 Java
Java多线程编程:实现线程间数据共享机制
以上就是Java中几种主要处理多线程序列化资源以及协调各自独立运行但需相互配合以完成任务threads 的技术手段与策略。正确应用上述技术将大大增强你程序稳定性与效率同时也降低bug出现率因此深刻理解每项技术背后理论至关重要.
57 16
|
17天前
|
NoSQL Java 关系型数据库
超全 Java 学习路线,帮你系统掌握编程的超详细 Java 学习路线
本文为超全Java学习路线,涵盖基础语法、面向对象编程、数据结构与算法、多线程、JVM原理、主流框架(如Spring Boot)、数据库(MySQL、Redis)及项目实战等内容,助力从零基础到企业级开发高手的进阶之路。
111 1
|
1月前
|
安全 算法 Java
Java泛型编程:类型安全与擦除机制
Java泛型详解:从基础语法到类型擦除机制,深入解析通配符与PECS原则,探讨运行时类型获取技巧及最佳实践,助你掌握泛型精髓,写出更安全、灵活的代码。
|
1月前
|
安全 Java Shell
Java模块化编程(JPMS)简介与实践
本文全面解析Java 9模块化系统(JPMS),帮助开发者解决JAR地狱、类路径冲突等常见问题,提升代码的封装性、性能与可维护性。内容涵盖模块化核心概念、module-info语法、模块声明、实战迁移、多模块项目构建、高级特性及最佳实践,同时提供常见问题和面试高频题解析,助你掌握Java模块化编程精髓,打造更健壮的应用。
|
3月前
|
Java 数据库连接 API
2025 更新必看:Java 编程基础入门级超级完整版指南
本教程为2025更新版Java编程基础入门指南,涵盖开发环境搭建(SDKMAN!管理JDK、VS Code配置)、Java 17+新特性(文本块、Switch表达式增强、Record类)、面向对象编程(接口默认方法、抽象类与模板方法)、集合框架深度应用(Stream API高级操作、并发集合)、模式匹配与密封类等。还包括学生成绩管理系统实战项目,涉及Maven构建、Lombok简化代码、JDBC数据库操作及JavaFX界面开发。同时提供JUnit测试、日志框架使用技巧及进阶学习资源推荐,助你掌握Java核心技术并迈向高级开发。
422 5
|
10月前
|
监控 安全 Java
Java中的多线程编程:从入门到实践####
本文将深入浅出地探讨Java多线程编程的核心概念、应用场景及实践技巧。不同于传统的摘要形式,本文将以一个简短的代码示例作为开篇,直接展示多线程的魅力,随后再详细解析其背后的原理与实现方式,旨在帮助读者快速理解并掌握Java多线程编程的基本技能。 ```java // 简单的多线程示例:创建两个线程,分别打印不同的消息 public class SimpleMultithreading { public static void main(String[] args) { Thread thread1 = new Thread(() -> System.out.prin
|
10月前
|
安全 Java 调度
Java中的多线程编程入门
【10月更文挑战第29天】在Java的世界中,多线程就像是一场精心编排的交响乐。每个线程都是乐团中的一个乐手,他们各自演奏着自己的部分,却又和谐地共同完成整场演出。本文将带你走进Java多线程的世界,让你从零基础到能够编写基本的多线程程序。
105 1