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

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
简介: 本文介绍了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天前
|
JSON Java Apache
非常实用的Http应用框架,杜绝Java Http 接口对接繁琐编程
UniHttp 是一个声明式的 HTTP 接口对接框架,帮助开发者快速对接第三方 HTTP 接口。通过 @HttpApi 注解定义接口,使用 @GetHttpInterface 和 @PostHttpInterface 等注解配置请求方法和参数。支持自定义代理逻辑、全局请求参数、错误处理和连接池配置,提高代码的内聚性和可读性。
|
7天前
|
存储 算法 Java
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
本文详解自旋锁的概念、优缺点、使用场景及Java实现。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
|
7天前
|
存储 安全 Java
Java多线程编程的艺术:从基础到实践####
本文深入探讨了Java多线程编程的核心概念、应用场景及其实现方式,旨在帮助开发者理解并掌握多线程编程的基本技能。文章首先概述了多线程的重要性和常见挑战,随后详细介绍了Java中创建和管理线程的两种主要方式:继承Thread类与实现Runnable接口。通过实例代码,本文展示了如何正确启动、运行及同步线程,以及如何处理线程间的通信与协作问题。最后,文章总结了多线程编程的最佳实践,为读者在实际项目中应用多线程技术提供了宝贵的参考。 ####
|
4天前
|
监控 安全 Java
Java中的多线程编程:从入门到实践####
本文将深入浅出地探讨Java多线程编程的核心概念、应用场景及实践技巧。不同于传统的摘要形式,本文将以一个简短的代码示例作为开篇,直接展示多线程的魅力,随后再详细解析其背后的原理与实现方式,旨在帮助读者快速理解并掌握Java多线程编程的基本技能。 ```java // 简单的多线程示例:创建两个线程,分别打印不同的消息 public class SimpleMultithreading { public static void main(String[] args) { Thread thread1 = new Thread(() -> System.out.prin
|
6天前
|
存储 缓存 安全
在 Java 编程中,创建临时文件用于存储临时数据或进行临时操作非常常见
在 Java 编程中,创建临时文件用于存储临时数据或进行临时操作非常常见。本文介绍了使用 `File.createTempFile` 方法和自定义创建临时文件的两种方式,详细探讨了它们的使用场景和注意事项,包括数据缓存、文件上传下载和日志记录等。强调了清理临时文件、确保文件名唯一性和合理设置文件权限的重要性。
16 2
|
7天前
|
Java UED
Java中的多线程编程基础与实践
【10月更文挑战第35天】在Java的世界中,多线程是提升应用性能和响应性的利器。本文将深入浅出地介绍如何在Java中创建和管理线程,以及如何利用同步机制确保数据一致性。我们将从简单的“Hello, World!”线程示例出发,逐步探索线程池的高效使用,并讨论常见的多线程问题。无论你是Java新手还是希望深化理解,这篇文章都将为你打开多线程的大门。
|
7天前
|
安全 Java 编译器
Java多线程编程的陷阱与最佳实践####
【10月更文挑战第29天】 本文深入探讨了Java多线程编程中的常见陷阱,如竞态条件、死锁、内存一致性错误等,并通过实例分析揭示了这些陷阱的成因。同时,文章也分享了一系列最佳实践,包括使用volatile关键字、原子类、线程安全集合以及并发框架(如java.util.concurrent包下的工具类),帮助开发者有效避免多线程编程中的问题,提升应用的稳定性和性能。 ####
33 1
|
13天前
|
安全 Java 调度
Java中的多线程编程入门
【10月更文挑战第29天】在Java的世界中,多线程就像是一场精心编排的交响乐。每个线程都是乐团中的一个乐手,他们各自演奏着自己的部分,却又和谐地共同完成整场演出。本文将带你走进Java多线程的世界,让你从零基础到能够编写基本的多线程程序。
28 1
|
19天前
|
Java 数据处理 开发者
Java多线程编程的艺术:从入门到精通####
【10月更文挑战第21天】 本文将深入探讨Java多线程编程的核心概念,通过生动实例和实用技巧,引导读者从基础认知迈向高效并发编程的殿堂。我们将一起揭开线程管理的神秘面纱,掌握同步机制的精髓,并学习如何在实际项目中灵活运用这些知识,以提升应用性能与响应速度。 ####
43 3
|
21天前
|
Java
Java中的多线程编程:从入门到精通
本文将带你深入了解Java中的多线程编程。我们将从基础概念开始,逐步深入探讨线程的创建、启动、同步和通信等关键知识点。通过阅读本文,你将能够掌握Java多线程编程的基本技能,为进一步学习和应用打下坚实的基础。