行业资讯 2025年08月6日
0 收藏 0 点赞 329 浏览 4191 个字
摘要 :

文章目录 1. 锁的状态管理 拓展(AbstractQueuedSynchronizer) 原理和结构 核心方法 使用AQS的优点 AQS的缺点 结论 2. 可重入性 3. 公平性与非公平性 4. 条件变量 5.……




  • 1. 锁的状态管理
    • 拓展(AbstractQueuedSynchronizer)
    • 原理和结构
    • 核心方法
    • 使用AQS的优点
    • AQS的缺点
    • 结论
  • 2. 可重入性
  • 3. 公平性与非公平性
  • 4. 条件变量
  • 5.ReentrantLock优点
    • 灵活性与功能性
    • 性能
    • 可重入性
  • 6.ReentrantLock缺点
    • 复杂性
    • 风险
    • 资源消耗
    • 锁的升级和降级不支持
  • 7.总结

本文重点讲解ReentrantLock的底层原理以及优缺点内容,为了深入了解Reentrant Lock的底层原理,我们需要从几个关键方面入手:锁的状态管理、可重入性、公平性与非公平性、以及条件变量的使用。接下来,我将详细解释这些方面。

1. 锁的状态管理

Reentrant Lock使用一个状态变量来表示锁的持有情况。这个状态通常用来表示锁被重入的次数。

// AbstractQueuedSynchronizer类中的部分代码
abstract static class Sync extends AbstractQueuedSynchronizer {
    // ...
    protected final boolean isHeldExclusively() {
        return getExclusiveOwnerThread() == Thread.currentThread();
    }
}

在上面的代码片段中,AbstractQueuedSynchronizer(AQS)是Reentrant Lock实现的基础。它使用getExclusiveOwnerThread()方法来检查当前线程是否是锁的持有者。

拓展(AbstractQueuedSynchronizer)

AbstractQueuedSynchronizer(简称AQS)是Java并发包中的一个核心类,它提供了一种有效的框架来实现依赖于先进先出(FIFO)等待队列的阻塞锁和相关的同步器(如信号量、事件等)。它是许多同步类的基础,包括ReentrantLockSemaphoreCountDownLatchFutureTask

原理和结构

状态(State): AQS使用一个整型的变量来表示同步状态。这个状态是同步器的核心,用于控制同步器是否被占用。

节点(Node)和等待队列: 当线程尝试获取同步状态失败时,AQS会将该线程包装成一个节点(Node)并将其加入到队列中。这个队列是一个FIFO队列,用于管理等待获取同步状态的线程。

独占模式和共享模式: AQS支持两种同步模式。独占模式在任何时候只允许一个线程持有同步状态,而共享模式允许多个线程同时持有同步状态。

核心方法

获取和释放方法:

acquire(int arg)release(int arg)用于实现独占式的获取和释放同步状态。

acquireShared(int arg)releaseShared(int arg)用于实现共享式的获取和释放同步状态。

同步状态管理方法:

getState(), setState(int newState), 和compareAndSetState(int expect, int update)用于管理同步状态。

等待队列管理方法:

hasQueuedThreads()hasContended()用来检查是否有线程在等待队列中。

使用AQS的优点

降低复杂性: AQS抽象了一系列复杂的同步控制逻辑,使得开发者可以通过实现几个方法来快速创建可靠的同步器。

高效和可靠: AQS提供的框架经过了良好的测试和优化,能够有效地管理线程间的同步。

灵活性: 支持独占和共享两种模式,可以满足不同场景的同步需求。

AQS的缺点

复杂性: 尽管AQS降低了实现同步器的复杂度,但理解其内部工作原理仍然需要一定的并发编程知识。

直接使用局限性: AQS是一个用于构建锁和同步器的框架,它本身在大多数情况下不直接用于编程。

结论

AbstractQueuedSynchronizer是Java并发编程中的一个重要组件。它通过提供一组方法来管理同步状态、实现锁的获取与释放,并管理等待获取锁的线程队列,从而为开发高效且可靠的同步器提供了坚实的基础。尽管它的直接使用相对复杂,但它背后的概念和机制对理解Java并发编程至关重要。

2. 可重入性

Reentrant Lock的可重入性是指同一个线程可以多次获取同一个锁。这是通过在锁内部记录锁的所有者以及锁的重入次数来实现的。

public void lock() {
    sync.lock();
}

protected final boolean tryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
    if (c == 0) {
        if (compareAndSetState(0, acquires)) {
            setExclusiveOwnerThread(current);
            return true;
        }
    }
    else if (current == getExclusiveOwnerThread()) {
        int nextc = c + acquires;
        if (nextc 0) // overflow
            throw new Error(\"Maximum lock count exceeded\");
        setState(nextc);
        return true;
    }
    return false;
}

在这段代码中,tryAcquire方法首先检查锁是否已经被占用(即状态c不为0)。如果没有被占用,它尝试设置当前线程为锁的所有者。如果已经被当前线程占用,它简单地增加重入计数。

3. 公平性与非公平性

Reentrant Lock提供了公平和非公平两种模式。在公平模式下,等待最久的线程会优先获取锁。而在非公平模式下,这种排序不被保证。

static final class FairSync extends Sync {
    final void lock() {
        acquire(1);
    }

    protected final boolean tryAcquire(int acquires) {
        final Thread current = Thread.currentThread();
        int c = getState();
        if (c == 0) {
            if (!hasQueuedPredecessors() && 
                compareAndSetState(0, acquires)) {
                setExclusiveOwnerThread(current);
                return true;
            }
        }
        else if (current == getExclusiveOwnerThread()) {
            int nextc = c + acquires;
            if (nextc 0)
                throw new Error(\"Maximum lock count exceeded\");
            setState(nextc);
            return true;
        }
        return false;
    }
}

在这里,FairSync类扩展了Sync,并重写了tryAcquire方法以添加检查是否有等待更久的线程。

4. 条件变量

Reentrant Lock使用Condition对象来支持线程间的协作,这允许在特定条件下挂起和通知线程。

public class ReentrantLock implements Lock, java.io.Serializable {
    private final Sync sync;

    public Condition newCondition() {
        return sync.newCondition();
    }

    abstract static class Sync extends AbstractQueuedSynchronizer {
        final ConditionObject newCondition() {
            return new ConditionObject();
        }
    }
}

在上述代码中,newCondition()方法创建一个新的ConditionObject实例,它是AbstractQueuedSynchronizer.ConditionObject的一个实例,提供了等待/通知的功能。

当讨论Reentrant Lock(可重入锁)的优势和劣势时,我们需要从多个角度来考虑,包括它在性能、灵活性、易用性以及其它方面的表现。

5.ReentrantLock优点

灵活性与功能性

  • 可中断的锁获取: Reentrant Lock允许在等待锁的过程中响应中断,这是synchronized无法提供的功能。
  • 尝试锁定与超时: 提供了tryLock()方法,可以尝试获取锁而不是无限期等待,还可以设置超时时间。
  • 公平锁选项: 可以选择创建一个公平锁,确保按照请求的顺序获得锁,而synchronized总是非公平的。
  • 支持多个条件变量: Reentrant Lock可以与多个Condition实例一起使用,允许更复杂的线程间协调。

性能

在高并发环境中,特别是锁竞争不是特别激烈的情况下,Reentrant Lock通常提供比synchronized更好的性能。

可重入性

允许同一个线程多次获得同一把锁,减少了死锁的风险。

6.ReentrantLock缺点

复杂性

相对于synchronized,Reentrant Lock的使用更复杂,需要手动管理锁的获取和释放,增加了编程的复杂性。

风险

  • 错误的使用(如忘记释放锁)可能导致严重问题,例如死锁或资源泄漏。
  • 由于Reentrant Lock不是自动管理的,因此在异常处理中必须非常小心,确保在finally块中释放锁。

资源消耗

相比synchronized,Reentrant Lock可能在某些情况下更加消耗资源,特别是在使用公平锁的情况下。

锁的升级和降级不支持

Reentrant Lock不支持锁的升级(从读锁升级为写锁)和降级(从写锁降级为读锁),这在某些场景下可能是一个限制。

7.总结

Reentrant Lock在灵活性、功能性和性能方面提供了显著的优势,特别适合于需要高级同步特性的复杂应用场景。然而,这些优势也伴随着更高的复杂性和潜在的风险。

因此,选择Reentrant Lock还是synchronized需要根据具体的应用场景和需求来决定。简单场景下,使用synchronized可能更为合适,因为它更简单且在JVM层面得到了优化。而在复杂的多线程应用中,Reentrant Lock的高级功能可能更有价值。

以上就是ReentrantLock的底层原理以及优缺点的全部内容,你学会了吗?

微信扫一扫

支付宝扫一扫

版权: 转载请注明出处:https://www.zuozi.net/9731.html

管理员

相关推荐
2025-08-06

文章目录 一、Reader 接口概述 1.1 什么是 Reader 接口? 1.2 Reader 与 InputStream 的区别 1.3 …

988
2025-08-06

文章目录 一、事件溯源 (一)核心概念 (二)Kafka与Golang的优势 (三)完整代码实现 二、命令…

465
2025-08-06

文章目录 一、证明GC期间执行native函数的线程仍在运行 二、native线程操作Java对象的影响及处理方…

348
2025-08-06

文章目录 一、事务基础概念 二、MyBatis事务管理机制 (一)JDBC原生事务管理(JdbcTransaction)…

456
2025-08-06

文章目录 一、SnowFlake算法核心原理 二、SnowFlake算法工作流程详解 三、SnowFlake算法的Java代码…

517
2025-08-06

文章目录 一、本地Jar包的加载操作 二、本地Class的加载方法 三、远程Jar包的加载方式 你知道Groo…

832
发表评论
暂无评论

还没有评论呢,快来抢沙发~

助力内容变现

将您的收入提升到一个新的水平

点击联系客服

在线时间:08:00-23:00

客服QQ

122325244

客服电话

400-888-8888

客服邮箱

122325244@qq.com

扫描二维码

关注微信客服号