当前位置: 首页 > news >正文

解析JUC包底层源码实现

引言

上篇文章详细讲解了AQS底层架构,由等待队列和同步队列以及state信号量来实现,本篇文章将详细讲解JUC包是如何利用这些架构来实现各种组件的

ReentrantLock(可重入锁)

ReentrantLock 是一个独占锁,同一时刻只允许一个线程获取锁。它通过 AQS 的 state 变量来表示锁的重入次数,state 为 0 表示锁未被持有,大于 0 表示锁已被持有,且值表示持有线程的重入次数。

实现细节:

获取锁:ReentrantLock 有公平锁和非公平锁两种实现,它们都继承自 AQS 并重写了 tryAcquire 方法。以非公平锁为例,当线程尝试获取锁时,会先检查 state 是否为 0,如果是则尝试使用 CAS 操作将 state 设为 1,表示获取锁成功;如果 state 不为 0 且当前线程就是持有锁的线程,则将 state 加 1,表示重入。

static final class NonfairSync extends Sync {
    final void lock() {
        if (compareAndSetState(0, 1))
            setExclusiveOwnerThread(Thread.currentThread());
        else
            acquire(1);
    }

    protected final boolean tryAcquire(int acquires) {
        return nonfairTryAcquire(acquires);
    }
}

释放锁:重写 tryRelease 方法,每次释放锁时将 state 减 1,当 state 减为 0 时,表示锁完全释放,此时会唤醒等待队列中的后继节点。

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;
}

CountDownLatch(倒计时锁存器)

CountDownLatch 用于让一个或多个线程等待其他线程完成操作。它通过 AQS 的 state 变量作为计数器,初始值为需要等待的操作数量,每当一个操作完成时,调用 countDown() 方法将 state 减 1,当 state 减为 0 时,等待的线程会被唤醒。

实现细节:

初始化:在构造函数中设置 state 的初始值。

public CountDownLatch(int count) {
    if (count < 0) throw new IllegalArgumentException("count < 0");
    this.sync = new Sync(count);
}

private static final class Sync extends AbstractQueuedSynchronizer {
    Sync(int count) {
        setState(count);
    }
}

等待操作完成:调用 await() 方法,线程会尝试获取共享锁,只有当 state 为 0 时才能获取成功,否则线程会进入等待队列。

public void await() throws InterruptedException {
    sync.acquireSharedInterruptibly(1);
}

操作完成通知:调用 countDown() 方法,会将 state 减 1,当 state 减为 0 时,会唤醒等待队列中的所有线程。

public void countDown() {
    sync.releaseShared(1);
}

Semaphore(信号量)

Semaphore 用于控制同时访问某个资源的线程数量。它通过 AQS 的 state 变量表示可用的许可数量,线程在访问资源前需要先获取许可(acquire()),访问完成后释放许可(release())。

实现细节:

获取许可:调用 acquire() 方法,线程会尝试获取共享锁,通过减少 state 的值来表示获取许可。如果 state 小于请求的许可数量,则线程会进入等待队列。

public void acquire() throws InterruptedException {
    sync.acquireSharedInterruptibly(1);
}

释放许可:调用 release() 方法,会增加 state 的值,表示释放许可,同时会唤醒等待队列中的线程。

public void release() {
    sync.releaseShared(1);
}

相关文章:

  • 3.5 使用Tokenizer编解码文本:从原理到企业级实践
  • ArcGIS笔记之度分秒与十进制度的转换
  • 【分治法】棋盘覆盖问题 C/C++(附代码和测试实例及算法分析)
  • C语言——字符串
  • Udp发送和接收数据(python和QT)
  • 2025-02-18 学习记录--C/C++-PTA 7-25 念数字
  • 鱼骨图技能详解
  • macos安装jmeter测试软件
  • PHP语法入门完全指南(2024新版)
  • 【Spring】Spring配置文件
  • MapReduce远程调试
  • 如何利用快捷指令制作快递取件码提醒?
  • Java 反射机制深度解析:类信息的来源、declared 的区别、赋值操作及暴力反射
  • 如何避免redis长期运行持久化AOF文件过大的问题:AOF重写
  • Docker安装Quickwit搜索引擎
  • 捷米特 JM - RTU - TCP 网关应用 F - net 协议转 Modbus TCP 实现电脑控制流量计
  • 【gRPC】:快速上手gRPC与protobuf
  • 深入理解 C++17 中的 std::launder
  • 常用标准库之-std::iota
  • 初等数论--欧几里得算法
  • 重庆荣昌区委区政府再设“答谢宴”,邀请800余名志愿者机关食堂用餐
  • 卢正已任上海市司法局党委委员、副局长
  • 呼和浩特推进新一轮国企重组整合:杜绝一项目一公司、一业务一公司
  • “科创板八条”后百单产业并购发布,披露交易金额超247亿
  • 央行、证监会:科技创新债券含公司债券、企业债券、非金融企业债务融资工具等
  • 第四轮伊美核问题谈判预计5月11日举行