Java中的ReentrantLock实现原理

这篇具有很好参考价值的文章主要介绍了Java中的ReentrantLock实现原理。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Java中的ReentrantLock实现原理

在并发编程中,线程安全问题一直是非常重要的问题。Java中提供了多种解决线程安全问题的机制,其中一个比较常用的就是ReentrantLock。本文将介绍ReentrantLock的实现原理,从原子性、可见性等方面解释并结合源码分析,以便更好地理解在多线程环境下实现线程安全的过程。

ReentrantLock概述

ReentrantLock是Java并发包下的一个类,它提供了与synchronized关键字类似的功能,可以实现对共享资源的访问控制,从而保证线程安全。相比于synchronized关键字,ReentrantLock需要更为复杂的使用方式,但是其灵活性更强,同时可以支持更高级别的需求。

ReentrantLock的构造函数可以接受一个参数fair,表示是否采用公平锁方式,默认为false,即非公平锁。

为什么需要ReentrantLock

synchronized关键字是Java中最基本的线程同步机制,其优点是简单易用,但是其缺点也是显而易见的。由于synchronized关键字是Java语言级别的,因此其性能较差,且不容易进行灵活的定制。当需要使用比较复杂的同步机制时,synchronized关键字就显得力不足。

而ReentrantLock通过提供可定制的同步机制,弥补了synchronized关键字的缺点。ReentrantLock的使用方式更为灵活,支持多种同步策略,可以很好地满足不同的需求。同时,由于ReentrantLock是基于Java并发包中的API实现的,因此它的运行效率较高。

ReentrantLock实现原理

ReentrantLock的实现原理可以分为两个方面,即锁的获取和锁的释放。

锁的获取

在ReentrantLock中,锁的获取是通过调用lock()方法来实现的。其核心思想是:当一个线程请求一个未被锁定的ReentrantLock时,该线程将获得锁并进入临界区,阻止其他线程进入临界区;当另一个线程请求相同的锁时,如果该锁已经被另一个线程占用,则该线程会被阻塞,并一直等待直到该锁被释放后才能重新尝试获取该锁。

但是,ReentrantLock的获取锁过程并不是简单地采用同步机制来实现的,而是涉及到一些底层的机制。具体来说,ReentrantLock采用了以下三种机制来实现锁的获取:

1. 原子性

在ReentrantLock的实现中,对于每个线程来说都会有一个state变量,其代表当前线程获取到的锁重入次数。当一个线程首次获取锁时,state的值为0。如果该线程再次获取锁,state的值就会增加1。相应地,当该线程释放锁时,state值将减少1。

这样一来,在ReentrantLock中,锁的获取过程就涉及到了原子性的问题。因此,ReentrantLock使用了CAS(Compare and Swap)机制来确保锁的获取操作是原子性的。简单来说,CAS机制就是在多线程环境下,当多个线程同时尝试修改同一个变量时,只有一个线程能够成功修改,其他线程将被阻塞。

2. 可重入性

在ReentrantLock中,还需要支持可重入性,即一个线程可以多次获取同一个锁。为了实现这个功能,ReentrantLock会为每个线程记录已经获取到的锁的状态信息,并确保在释放所有已获取的锁之前不允许其他线程获取这些锁。因此,ReentrantLock的可重入性是通过这种方式实现的。

3. 队列机制

除了原子性和可重入性外,ReentrantLock还采用了队列机制来确保锁的获取顺序。具体来说,当多个线程请求同一把锁时,它们会被加入到一个FIFO队列中。锁的所有者会在释放锁时,唤醒队列中的下一个线程,从而实现锁的获取顺序。

锁的释放

与锁的获取不同,锁的释放过程相对简单。在ReentrantLock中,锁的释放是通过调用unlock()方法来实现的。具体来说,当一个线程调用unlock()方法释放锁时,ReentrantLock会将该线程的state值减少1,如果state值变为0,则锁被完全释放,并允许其他线程尝试获取该锁。

ReentrantLock源码分析

通过上述的介绍,我们可以初步了解ReentrantLock的实现原理。现在,我们再来结合源码分析,更深入地理解ReentrantLock的工作原理。

构造函数

首先,我们来看一下ReentrantLock的构造方法:

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

public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
}

在构造函数中,ReentrantLock随机选择了一种同步机制,即公平锁(FairSync)和非公平锁(NonfairSync)。这两种同步机制都是基于AQS(AbstractQueuedSynchronizer)实现的。

  • 公平锁(FairSync):采用先进先出的队列机制,将等待时间最长的线程先获取锁,从而保证了不产生饥饿现象。
  • 非公平锁(NonfairSync):直接将获取锁请求分配给任意一个等待线程。

上述两种机制各有优缺点,ReentrantLock结合实际情况进行选择。

锁的获取

在ReentrantLock中,锁的获取过程是通过调用lock()方法来实现的。我们来看一下NonfairSync的lock()方法实现:

final void lock() {
    if (compareAndSetState(0, 1))
        setExclusiveOwnerThread(Thread.currentThread());
    else
        acquire(1);
}

在上面的代码中,首先会对state值进行CAS操作,如果state的值为0,则当前线程获取到锁,并将state值设置为1;否则调用acquire()方法实现锁的获取。

在NonfairSync中,acquire()方法的实现如下:

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

该方法首先会调用tryAcquire()方法尝试获取锁。如果tryAcquire()返回false,则调用acquireQueued()方法将当前线程加入到等待队列中,并自旋等待获取锁。

如果当前线程成功获取锁,则会调用setExclusiveOwnerThread(Thread.currentThread())方法将当前线程设置为该锁的所有者。

需要注意的是,当一个线程尝试获取锁时如果失败了,则该线程不会立即被加入到等待队列中,而是会自旋一定的次数(默认是10次),然后重新尝试获取锁。这种方式可以有效地减少加入等待队列的线程数量,从而提高程序的性能。

锁的释放

在ReentrantLock中,锁的释放是通过调用unlock()方法来实现的。具体来说,我们来看一下NonfairSync的unlock()方法实现:

protected final boolean tryRelease(int releases) {
    int c = getState() - releases;
    if (Thread.currentThread() != getExclusiveOwnerThread())
        throw new IllegalMonitorStateException();
    boolean free = false;
    if (c == 0) {
        free = true;
        setExclusiveOwnerThread(null);
    }
    setState(c);
    return free;
}

public final void unlock() {
    release(1);
}

在上述代码中,ReentrantLock首先会调用tryRelease()方法来释放锁。如果当前线程并非该锁的所有者,则抛出IllegalMonitorStateException异常。如果当前线程成功释放了锁,则将该锁的所有者设置为null,并将state值更新为0。

需要注意的是,在调用unlock()方法释放锁时并没有使用synchronized关键字或者其他同步机制,而是通过调用tryRelease()方法来实现的。

小结

ReentrantLock是Java并发包下的一个基本类,它通过提供灵活的同步机制来保证线程安全。ReentrantLock的实现原理涉及到一些底文章来源地址https://www.toymoban.com/news/detail-429901.html

到了这里,关于Java中的ReentrantLock实现原理的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java中的Iterator底层原理实现

    Iterator主要有 两个抽象方法 ,让子类实现。 hasNext ()用来判断还有没有数据可供访问。 next ()方法用于访问集合的下一个数据。 这两个方法不像List的get()那样依赖索引获取数据,也不像Queue的poll方法那样依赖特定规则获取数据。 迭代器的方法将通用性做到了极致, 可以访问

    2023年04月12日
    浏览(33)
  • 结合ReentrantLock来看AQS的原理

    ​ 队列同步器 AbstractQueuedSynchronizer(以下简称同步器),是用来构建锁或者其他同步组件的基础框架,它使用了一个 int 成员变量表示同步状态,通过内置的 FIFO 队列来完成资源获取线程的排队工作,并发包的作者(Doug Lea)期望它能够成为实现大部分同步需求的基础。 同步

    2024年02月16日
    浏览(35)
  • Java中的volatile关键字实现原理

    在并发编程中,线程之间的可见性问题是非常重要的一项难题。Java中提供了一种解决并发可见性问题的机制,即volatile。 在本文中,我们将会讲解Java中volatile的实现原理,为什么它能够保证可见性,以及背后的实现原理涉及到的内存屏障和JVM屏障等内容。在学习

    2023年04月27日
    浏览(43)
  • ReentrantLock原理--非公平锁、可重入、可打断性

    先从构造器开始看,默认为非公平锁实现 NonfairSync 继承自 AQS 没有竞争时 第一个竞争出现时 Thread-1 执行了 CAS 尝试将 state 由 0 改为 1,结果失败 进入 tryAcquire 逻辑,这时 state 已经是1,结果仍然失败 接下来进入 addWaiter 逻辑,构造 Node 队列 图中黄色三角表示该 Node 的 waitSt

    2023年04月08日
    浏览(31)
  • java中的线程不安全和实例解析,网络安全多态实现原理

    先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7 深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前! 因此收集整理了一份《2024年最新网络安全全套学习资料》

    2024年04月27日
    浏览(44)
  • Java中的单点登录原理与实现方案探究:深入了解安全与便捷的用户认证解决方案

    目录 1、什么是单点登录 2、单点登录的优势和应用场景 3、单点登录的原理和实现方式 3.1 传统的Cookie和Session实现方式 3.2 基于Token的实现方式 3.3 基于OAuth2的实现方式 4、单点登录的技术要点和关键问题 4.1 安全性考虑 4.2 用户体验优化 4.3 高可用性设计 5、Java中的单点登录实

    2024年01月23日
    浏览(59)
  • 【后端面经-Java】Synchronize和ReentrantLock区别

    1.1 线程安全锁 Synchronize(同步锁)和ReentrantLock(可重入锁)都是Java中的常用锁,都是用来保证线程安全的。 两者都是同步锁,且都是阻塞同步。 阻塞同步:当一个线程获取锁后,其他线程只能等待(进入阻塞态),等待获取锁的线程释放锁后,其他线程才能获取锁。 1.2

    2024年02月11日
    浏览(39)
  • java ReentrantLock 锁 await、signal的用法

    在并发编程中,为了保证线程的原子执行,需要使用锁,jvm 内 可以使用 synchronized 和 ReentrantLock,如果是集群部署,我们可以使用Redis 分布式锁 其他的锁后面再介绍。 1、ReentrantLock 通过方法 lock()与 unlock()来进行加锁与解锁操作,与synchronized(1.8之后性能得到提升)会被JVM自动

    2024年02月11日
    浏览(77)
  • 深入源码解析 ReentrantLock、AQS:掌握 Java 并发编程关键技术

    🔭 嗨,您好 👋 我是 vnjohn,在互联网企业担任 Java 开发,CSDN 优质创作者 📖 推荐专栏:Spring、MySQL、Nacos、Java,后续其他专栏会持续优化更新迭代 🌲文章所在专栏:JUC 🤔 我当前正在学习微服务领域、云原生领域、消息中间件等架构、原理知识 💬 向我询问任何您想要的

    2024年02月11日
    浏览(51)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包