导读:本期聚焦于小伙伴创作的《Java中的AbstractQueuedSynchronizer是什么?如何实现自定义同步器》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《Java中的AbstractQueuedSynchronizer是什么?如何实现自定义同步器》有用,将其分享出去将是对创作者最好的鼓励。

AbstractQueuedSynchronizer是Java并发编程中非常重要的基础类,位于java.util.concurrent.locks包下,它提供了一套通用的机制来实现依赖先进先出等待队列的阻塞锁和相关的同步器。很多我们日常使用的并发工具都基于AQS实现,比如ReentrantLock、Semaphore、ReentrantReadWriteLock等,理解AQS的工作原理能帮助我们更深入地掌握这些工具的实现逻辑。

Java中的AbstractQueuedSynchronizer是什么?如何实现自定义同步器

AQS的核心结构

AQS的核心设计包含两个部分,一个是volatile修饰的int类型状态变量state,另一个是内置的先进先出双向等待队列,用来存放获取资源失败的线程。

状态变量state

state是AQS的核心控制变量,不同的同步器对state的含义有不同的定义。比如ReentrantLock中state表示锁的重入次数,state为0表示锁未被占用,大于0表示锁被占用且记录了重入次数;Semaphore中state表示剩余的许可证数量。

AQS提供了三个protected方法用来操作state:

  • getState():获取当前state值
  • setState(int newState):直接设置state值
  • compareAndSetState(int expect, int update):使用CAS操作原子更新state值

等待队列

AQS的等待队列是一个双向链表,每个节点对应一个等待获取资源的线程。节点包含线程引用、等待状态等信息,队列的头节点是虚拟节点,不包含实际线程,真正的等待线程从第二个节点开始存放。

AQS的两种资源共享模式

AQS支持两种资源共享模式,子类同步器需要根据自己的需求选择其中一种实现对应的方法:

模式说明典型实现
独占模式同一时间只有一个线程能获取资源,其他线程需要进入等待队列ReentrantLock
共享模式同一时间可以有多个线程获取资源,超过资源数量限制的线程进入等待队列Semaphore、CountDownLatch

自定义同步器的实现步骤

如果要基于AQS实现自定义同步器,需要创建一个AQS的子类,然后根据选择的资源共享模式,重写对应的模板方法。AQS提供了以下需要重写的protected方法:

  • tryAcquire(int arg):独占模式下尝试获取资源,成功返回true,失败返回false
  • tryRelease(int arg):独占模式下尝试释放资源,成功返回true,失败返回false
  • tryAcquireShared(int arg):共享模式下尝试获取资源,返回负数表示失败,0表示获取成功但没有剩余资源,正数表示获取成功且还有剩余资源
  • tryReleaseShared(int arg):共享模式下尝试释放资源,成功返回true,失败返回false
  • isHeldExclusively():判断当前同步器是否被独占,一般在独占模式下需要实现

实现独占模式的自定义锁

下面我们实现一个简单的独占锁,同一时间只允许一个线程持有锁,支持重入:

import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Lock;

// 自定义独占锁,基于AQS实现
public class CustomLock implements Lock {

    // 内部同步器类,继承AQS
    private static class Sync extends AbstractQueuedSynchronizer {
        // 尝试获取锁,state为0表示锁未被占用
        @Override
        protected boolean tryAcquire(int arg) {
            // 使用CAS将state从0更新为1,更新成功表示获取锁成功
            if (compareAndSetState(0, arg)) {
                // 设置当前持有锁的线程
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            // 如果当前线程已经是锁的持有者,支持重入,增加state值
            if (getExclusiveOwnerThread() == Thread.currentThread()) {
                setState(getState() + arg);
                return true;
            }
            return false;
        }

        // 尝试释放锁
        @Override
        protected boolean tryRelease(int arg) {
            // 如果当前线程不是锁的持有者,抛出异常
            if (getExclusiveOwnerThread() != Thread.currentThread()) {
                throw new IllegalMonitorStateException();
            }
            // 减少state值
            int nextState = getState() - arg;
            boolean released = false;
            // state减为0表示锁完全释放
            if (nextState == 0) {
                setExclusiveOwnerThread(null);
                released = true;
            }
            setState(nextState);
            return released;
        }

        // 判断锁是否被当前线程独占
        @Override
        protected boolean isHeldExclusively() {
            return getExclusiveOwnerThread() == Thread.currentThread();
        }
    }

    private final Sync sync = new Sync();

    @Override
    public void lock() {
        // 调用AQS的acquire方法,会触发tryAcquire
        sync.acquire(1);
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }

    @Override
    public boolean tryLock() {
        return sync.tryAcquire(1);
    }

    @Override
    public boolean tryLock(long time, java.util.concurrent.TimeUnit unit) throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(time));
    }

    @Override
    public void unlock() {
        // 调用AQS的release方法,会触发tryRelease
        sync.release(1);
    }

    @Override
    public java.util.concurrent.locks.Condition newCondition() {
        return sync.new ConditionObject();
    }
}

自定义同步器的测试

我们可以编写一个简单的测试代码验证自定义锁的功能:

public class CustomLockTest {
    private static int count = 0;
    private static final CustomLock lock = new CustomLock();

    public static void main(String[] args) throws InterruptedException {
        // 创建10个线程对count进行累加
        Thread[] threads = new Thread[10];
        for (int i = 0; i < 10; i++) {
            threads[i] = new Thread(() -> {
                lock.lock();
                try {
                    // 临界区操作,对count加1000
                    for (int j = 0; j < 1000; j++) {
                        count++;
                    }
                } finally {
                    // 确保锁一定会被释放
                    lock.unlock();
                }
            });
        }

        // 启动所有线程
        for (Thread thread : threads) {
            thread.start();
        }

        // 等待所有线程执行完成
        for (Thread thread : threads) {
            thread.join();
        }

        // 最终结果应该是10000
        System.out.println("最终count值:" + count);
    }
}

运行上述测试代码,最终输出的count值为10000,说明我们的自定义独占锁正确地实现了线程同步功能。

AQS的工作流程总结

当线程尝试获取资源时,首先会调用我们重写的tryAcquire或tryAcquireShared方法,如果获取成功就直接返回;如果获取失败,AQS会把当前线程封装成节点加入等待队列的尾部,然后让线程进入阻塞状态。当持有资源的线程释放资源时,会调用我们重写的tryRelease或tryReleaseShared方法,释放成功后AQS会唤醒等待队列中的头节点后面的第一个等待线程,让它重新尝试获取资源。

理解AQS的这套工作流程,就能明白为什么基于它实现的同步器都能保证线程安全,也能根据业务需求灵活地实现各种自定义同步组件。

AbstractQueuedSynchronizerAQS自定义同步器Java并发修改时间:2026-07-16 15:42:41

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。