JUC之AQS

文章目录

  • 一、AQS核心概念与设计哲学
    • [1.1 AQS是什么?](#1.1 AQS是什么?)
    • [1.2 AQS的核心数据结构](#1.2 AQS的核心数据结构)
  • 二、AQS核心原理深度解析
    • [2.1 同步状态【state】管理](#2.1 同步状态【state】管理)
    • [2.2 CLH队列的工作原理](#2.2 CLH队列的工作原理)
    • [2.3 模板方法模式](#2.3 模板方法模式)
  • 三、AQS两种同步模式
    • [3.1 独占模式(Exclusive)](#3.1 独占模式(Exclusive))
      • [3.1.1 独占模式获取资源](#3.1.1 独占模式获取资源)
      • [3.1.2 关键辅助方法解析](#3.1.2 关键辅助方法解析)
      • [3.1.3 独占模式释放资源](#3.1.3 独占模式释放资源)
    • [3.2 共享模式(Shared)](#3.2 共享模式(Shared))
      • [3.2.1 共享模式获取资源](#3.2.1 共享模式获取资源)
      • [3.2.2 共享模式释放资源](#3.2.2 共享模式释放资源)
  • 四、基于AQS的实现示例
    • [4.1 自定义互斥锁](#4.1 自定义互斥锁)
    • [4.2 CustomMutex使用示例](#4.2 CustomMutex使用示例)
    • [4.3 不可重入互斥锁(Mutex)](#4.3 不可重入互斥锁(Mutex))
    • [4.4 二元信号量(BinarySemaphore)](#4.4 二元信号量(BinarySemaphore))
    • [4.5 自定义高级同步器](#4.5 自定义高级同步器)
  • 五、AQS在JUC中的实际应用
    • [5.1 ReentrantLock 中的 AQS 应用](#5.1 ReentrantLock 中的 AQS 应用)
    • [5.2 CountDownLatch 中的 AQS 应用](#5.2 CountDownLatch 中的 AQS 应用)
  • 六、AQS高级特性
      • [6.1 条件变量(Condition)的实现](#6.1 条件变量(Condition)的实现)
    • [6.2 Condition示例](#6.2 Condition示例)
  • 七、AQS性能优化与最佳实践
    • [7.1 最佳实践总结](#7.1 最佳实践总结)
    • [7.2 使用经验](#7.2 使用经验)
      • [❌ 避免陷阱](#❌ 避免陷阱)
  • 八、总结AQS

一、AQS核心概念与设计哲学

1.1 AQS是什么?

AbstractQueuedSynchronizer(AQS)是 Java 并发包 (java.util.concurrent.locks) 中的核心框架,用于构建锁和其他同步器的基础。它提供了一个基于 FIFO 等待队列的同步器框架,JUC 中的大多数同步工具如 ReentrantLock、Semaphore、CountDownLatch 都是基于 AQS 构建的。

核心设计思想

  • 状态管理:使用一个 volatile int 类型的 state 变量表示同步状态
  • 队列管理:通过内置的 FIFO 队列管理获取同步状态失败的线程
  • 模板方法:通过模板方法模式,子类通过继承并实现指定方法管理同步状态

基于AQS的实现 AQS 核心架构 ReentrantLock Semaphore CountDownLatch CyclicBarrier ReentrantReadWriteLock AQS volatile int state
同步状态 CLH队列
FIFO线程等待队列 独占模式
如ReentrantLock 共享模式
如Semaphore

1.2 AQS的核心数据结构

java 复制代码
// AQS 简化核心结构
public abstract class AbstractQueuedSynchronizer {
    
    // 同步状态,volatile保证可见性
    private volatile int state;
    
    // CLH队列头节点
    private transient volatile Node head;
    
    // CLH队列尾节点
    private transient volatile Node tail;
    
    // CLH队列节点定义
    static final class Node {
        // 节点模式:共享、独占
        static final Node SHARED = new Node();
        static final Node EXCLUSIVE = null;
        
        // 等待状态
        volatile int waitStatus;
        
        // 前驱和后继节点
        volatile Node prev;
        volatile Node next;
        
        // 节点关联的线程
        volatile Thread thread;
    }
}

二、AQS核心原理深度解析

组件 说明
state int 类型,表示同步状态。由 volatile 修饰,保证可见性。
head / tail 指向同步队列的头节点和尾节点。
Node 队列中的节点,封装等待线程及其等待状态。
CLH 队列变体 AQS 使用的是 CLH 锁队列的变体,用于管理等待线程。

2.1 同步状态【state】管理

AQS 使用一个整型的 state 来表示同步状态,不同的子类对其有不同的解释:

  • ReentrantLock:state 表示锁的重入次数(0表示未锁定,>0表示重入次数)
  • Semaphore:state 表示可用的许可数量
  • CountDownLatch:state 表示计数器值
  • ReentrantReadWriteLock:高16位表示读锁数量,低16位表示写锁重入次数

2.2 CLH队列的工作原理

AQS 使用 CLH 变体的双向队列来管理等待线程。CLH 队列是一个 FIFO 队列,具有以下特性:

  1. 公平性:保证等待时间最长的线程最先获取锁
  2. 高效性:通过前驱节点的状态来减少不必要的线程唤醒
  3. 可扩展性:支持大量线程的排队管理

node的节点结构

java 复制代码
static final class Node {
    volatile int waitStatus;     // 等待状态
    volatile Node prev;          // 前驱节点
    volatile Node next;          // 后继节点
    volatile Thread thread;      // 关联的线程
    Node nextWaiter;             // 下一个等待节点(用于条件队列)
}

等待状态的值

状态 含义
SIGNAL -1 当前节点的后继节点已被阻塞,需要当前节点释放时唤醒它。
CANCELLED 1 线程已取消(如中断或超时)。
CONDITION -2 节点在条件队列中。
PROPAGATE -3 共享模式下,释放操作应传播到后续节点。

同步队列结构
AQS 同步队列 Node: Thread A head Node: Thread B Node: Thread C tail

说明 :队列为双向链表,head 是虚拟头节点(不关联线程),tail 指向最后一个真实节点。

java 复制代码
// CLH队列操作的核心方法
private Node addWaiter(Node mode) {
    // 创建新节点,包含当前线程和模式(独占/共享)
    Node node = new Node(Thread.currentThread(), mode);
    
    // 快速尝试添加到队列尾部
    Node pred = tail;
    if (pred != null) {
        node.prev = pred;
        if (compareAndSetTail(pred, node)) {
            pred.next = node;
            return node;
        }
    }
    
    // 如果快速添加失败,使用完整入队流程
    enq(node);
    return node;
}

private Node enq(final Node node) {
    for (;;) { // 自旋直到成功入队
        Node t = tail;
        if (t == null) { // 队列为空,需要初始化
            if (compareAndSetHead(new Node())) // 设置哑节点
                tail = head;
        } else {
            node.prev = t;
            if (compareAndSetTail(t, node)) {
                t.next = node;
                return t;
            }
        }
    }
}

2.3 模板方法模式

AQS 使用模板方法模式,子类需要实现以下关键方法:

java 复制代码
public abstract class AbstractQueuedSynchronizer {
    // 尝试获取独占锁,需要子类实现
    protected boolean tryAcquire(int arg) {
        throw new UnsupportedOperationException();
    }
    
    // 尝试释放独占锁,需要子类实现
    protected boolean tryRelease(int arg) {
        throw new UnsupportedOperationException();
    }
    
    // 尝试获取共享锁,需要子类实现
    protected int tryAcquireShared(int arg) {
        throw new UnsupportedOperationException();
    }
    
    // 尝试释放共享锁,需要子类实现
    protected boolean tryReleaseShared(int arg) {
        throw new UnsupportedOperationException();
    }
    
    // 判断是否独占模式,需要子类实现
    protected boolean isHeldExclusively() {
        throw new UnsupportedOperationException();
    }
}

三、AQS两种同步模式

3.1 独占模式(Exclusive)

一次只有一个线程可以获取同步状态,如 ReentrantLock。

java 复制代码
// 独占模式获取同步状态的核心流程
public final void acquire(int arg) {
    if (!tryAcquire(arg) && // 首先尝试获取
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) // 失败则加入队列
        selfInterrupt(); // 如果等待过程中被中断,重新设置中断标志
}

// 独占模式获取同步状态的详细流程
public final void acquire(int arg) {
    if (!tryAcquire(arg)) { // 尝试获取锁失败
        Node node = addWaiter(Node.EXCLUSIVE); // 创建独占模式节点并入队
        boolean interrupted = false;
        for (;;) { // 自旋
            final Node p = node.predecessor(); // 获取前驱节点
            if (p == head && tryAcquire(arg)) { // 如果前驱是头节点且获取成功
                setHead(node); // 将自己设为头节点
                p.next = null; // 帮助GC
                return;
            }
            if (shouldParkAfterFailedAcquire(p, node) && // 检查是否需要park
                parkAndCheckInterrupt()) // park并检查中断
                interrupted = true;
        }
    }
}

独占模式获取锁流程

独占模式释放锁
成功 失败 线程调用 release(int arg) tryRelease(arg) unparkSuccessor(head) 获取 head 的 next 节点 LockSupport.unpark(next.thread) 唤醒线程继续执行 acquireQueued 释放失败

特点 :同一时间只有一个线程能获取同步资源(如ReentrantLock的独占锁)。

核心流程:线程获取资源→成功则执行→失败则加入等待队列并阻塞→资源释放后唤醒队列中的下一个线程。

3.1.1 独占模式获取资源

acquire (int arg)

acquire是 AQS 提供的模板方法,子类无需重写,直接调用即可。流程如下:

  1. 调用子类重写的tryAcquire(arg)

    尝试获取资源:

    • 成功:直接返回,线程继续执行;
    • 失败:执行后续步骤。
  2. 调用addWaiter(Node.EXCLUSIVE)创建独占模式的Node节点,并加入队列尾部;

  3. 调用acquireQueued(node, arg)让节点在队列中自旋等待,直到获取资源或被取消。

简化后的核心代码:

java 复制代码
public final void acquire(int arg) {
    // 1. 尝试获取资源,失败则加入队列并自旋等待
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) {
        // 若自旋过程中被中断,标记当前线程需要中断
        selfInterrupt();
    }
}

3.1.2 关键辅助方法解析

  1. tryAcquire(int arg)

抽象方法,由子类实现,定义 "如何获取资源" 的逻辑。AQS 中默认抛出UnsupportedOperationException,子类必须重写(如ReentrantLock)。示例(非公平锁的tryAcquire实现)

java 复制代码
protected final boolean tryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
    // 1. 若状态为0(无锁),尝试CAS获取锁
    if (c == 0) {
        if (compareAndSetState(0, acquires)) {
            // 2. 标记当前线程为锁持有者
            setExclusiveOwnerThread(current);
            return true;
        }
    }
    // 3. 若当前线程已持有锁(重入),增加state计数
    else if (current == getExclusiveOwnerThread()) {
        int nextc = c + acquires;
        if (nextc < 0) // 防止溢出
            throw new Error("Maximum lock count exceeded");
        setState(nextc);
        return true;
    }
    // 4. 其他情况,获取失败
    return false;
}
  1. addWaiter(Node mode)

创建节点并加入队列尾部(CAS 保证线程安全),流程如下:

java 复制代码
private Node addWaiter(Node mode) {
    // 1. 创建当前线程的Node节点(mode为EXCLUSIVE或SHARED)
    Node node = new Node(Thread.currentThread(), mode);
    Node pred = tail;
    // 2. 若队列不为空,直接尝试CAS将节点加入尾部
    if (pred != null) {
        node.prev = pred;
        if (compareAndSetTail(pred, node)) {
            pred.next = node;
            return node;
        }
    }
    // 3. 队列为空或CAS失败,通过enq方法自旋加入队列
    enq(node);
    return node;
}

// 自旋CAS加入队列,确保节点被成功添加
private Node enq(final Node node) {
    for (;;) {
        Node t = tail;
        if (t == null) { // 队列空,初始化头节点(虚拟节点)
            if (compareAndSetHead(new Node()))
                tail = head;
        } else { // 队列非空,CAS添加到尾部
            node.prev = t;
            if (compareAndSetTail(t, node)) {
                t.next = node;
                return t;
            }
        }
    }
}
  1. acquireQueued(final Node node, int arg)

节点在队列中自旋等待,核心逻辑是 "前驱节点是头节点时,再次尝试获取资源;否则阻塞当前线程",流程如下:

java 复制代码
final boolean acquireQueued(final Node node, int arg) {
    boolean failed = true;
    try {
        boolean interrupted = false;
        // 自旋循环,直到获取资源或被取消
        for (;;) {
            final Node p = node.predecessor(); // 获取前驱节点
            // 1. 若前驱是头节点,尝试获取资源
            if (p == head && tryAcquire(arg)) {
                setHead(node); // 2. 获取成功,将当前节点设为头节点(原头节点被GC回收)
                p.next = null; // 3. 断开原头节点的引用,避免内存泄漏
                failed = false;
                return interrupted; // 4. 返回是否被中断过
            }
            // 5. 若获取失败,判断是否需要阻塞当前线程
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt()) {
                // 6. 若线程被中断,标记interrupted为true
                interrupted = true;
            }
        }
    } finally {
        if (failed) {
            // 7. 若获取资源失败且发生异常,取消当前节点
            cancelAcquire(node);
        }
    }
}

其中,shouldParkAfterFailedAcquire方法用于设置前驱节点的状态为SIGNAL,确保后续能被唤醒;parkAndCheckInterrupt方法通过LockSupport.park(this)阻塞当前线程,并返回是否被中断。

3.1.3 独占模式释放资源

release (int arg)

release也是模板方法,用于释放资源并唤醒队列中的下一个线程,流程如下:

  1. 调用子类重写的tryRelease(arg)

    尝试释放资源:

    • 成功:执行后续步骤;
    • 失败:直接返回false
  2. 唤醒队列中的下一个节点(若存在)。

简化后的核心代码

java 复制代码
public final boolean release(int arg) {
    // 1. 尝试释放资源
    if (tryRelease(arg)) {
        Node h = head;
        // 2. 若头节点不为空且状态不是初始状态,唤醒下一个节点
        if (h != null && h.waitStatus != 0) {
            unparkSuccessor(h);
        }
        return true;
    }
    return false;
}

tryRelease 示例(ReentrantLock 实现)

java 复制代码
protected final boolean tryRelease(int releases) {
    int c = getState() - releases;
    // 1. 只有锁持有者才能释放锁
    if (Thread.currentThread() != getExclusiveOwnerThread())
        throw new IllegalMonitorStateException();
    boolean free = false;
    // 2. 若state减为0,说明锁已完全释放
    if (c == 0) {
        free = true;
        setExclusiveOwnerThread(null); // 清除锁持有者
    }
    setState(c); // 更新状态
    return free;
}

unparkSuccessor 方法 :唤醒头节点的后继节点(跳过CANCELLED状态的节点),核心逻辑是通过LockSupport.unpark(s.thread)唤醒线程。

3.2 共享模式(Shared)

特点 :同一时间多个线程可同时获取同步资源(如SemaphoreCountDownLatch)。

核心流程与独占模式类似,但差异在于:

  • 共享模式下,线程获取资源成功后,会继续唤醒后续等待的共享线程(如CountDownLatchcountDown后,所有等待线程被唤醒);
  • 核心方法为acquireShared(int arg)(获取资源)和releaseShared(int arg)(释放资源)。
java 复制代码
// 共享模式获取同步状态
public final void acquireShared(int arg) {
    if (tryAcquireShared(arg) < 0) // 尝试获取
        doAcquireShared(arg); // 失败则加入队列
}

// 共享模式获取的详细实现
private void doAcquireShared(int arg) {
    final Node node = addWaiter(Node.SHARED); // 创建共享模式节点
    boolean interrupted = false;
    try {
        for (;;) { // 自旋
            final Node p = node.predecessor(); // 前驱节点
            if (p == head) {
                int r = tryAcquireShared(arg); // 尝试获取共享锁
                if (r >= 0) { // 获取成功
                    setHeadAndPropagate(node, r); // 设置头节点并传播
                    p.next = null; // 帮助GC
                    return;
                }
            }
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                interrupted = true;
        }
    } finally {
        if (interrupted)
            selfInterrupt();
    }
}

释放共享资源 获取共享资源 是 否 是 成功 tryReleaseShared(arg) releaseShared(arg) doReleaseShared() 唤醒 head.next 若为共享节点, 继续传播 tryAcquireShared(arg) >= 0 acquireShared(arg) 获取成功 doAcquireShared(arg) addWaiter(SHARED) 自旋 + 尝试获取 获取成功? setHeadAndPropagate() 传播唤醒后续共享节点

3.2.1 共享模式获取资源

acquireShared (int arg)

模板方法,流程如下:

  1. 调用子类重写的tryAcquireShared(arg)

    尝试获取资源:

    • 返回值>=0:获取成功,返回;
    • 返回值<0:获取失败,加入队列并阻塞。
  2. 若获取失败,调用doAcquireShared(arg)将节点加入队列并自旋等待。

简化后的核心代码

java 复制代码
public final void acquireShared(int arg) {
    if (tryAcquireShared(arg) < 0) {
        doAcquireShared(arg); // 加入队列并自旋
    }
}

tryAcquireShared 示例(Semaphore 实现)

java 复制代码
protected int tryAcquireShared(int acquires) {
    for (;;) {
        int available = getState();
        int remaining = available - acquires;
        // 1. 若可用许可不足,或CAS修改许可失败,继续自旋
        if (remaining < 0 ||
            compareAndSetState(available, remaining)) {
            return remaining; // 返回剩余许可(<0表示获取失败)
        }
    }
}

3.2.2 共享模式释放资源

releaseShared (int arg)

模板方法,流程如下:

  1. 调用子类重写的tryReleaseShared(arg)尝试释放资源(CAS 确保原子性);
  2. 若释放成功,唤醒队列中的后续共享节点。

简化后的核心代码

java 复制代码
public final boolean releaseShared(int arg) {
    if (tryReleaseShared(arg)) {
        doReleaseShared(); // 唤醒后续节点
        return true;
    }
    return false;
}

tryReleaseShared 示例(Semaphore 实现)

java 复制代码
protected final boolean tryReleaseShared(int releases) {
    for (;;) {
        int current = getState();
        int next = current + releases;
        if (next < current) // 防止溢出
            throw new Error("Maximum permit count exceeded");
        // CAS修改许可数量,成功则返回true
        if (compareAndSetState(current, next))
            return true;
    }
}

四、基于AQS的实现示例

4.1 自定义互斥锁

java 复制代码
package cn.tcmeta.aqs;

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

/**
 * 基于AQS的自定义互斥锁实现
 * 演示AQS独占模式的基本用法
 */
public class CustomMutex implements Lock {
    private final Sync sync = new Sync();
    
    // 自定义同步器,继承AQS
    private static class Sync extends AbstractQueuedSynchronizer {
        // 是否被占用
        @Override
        protected boolean isHeldExclusively() {
            return getState() == 1;
        }
        
        // 尝试获取锁
        @Override
        public boolean tryAcquire(int acquires) {
            // 使用CAS操作尝试将state从0改为1
            if (compareAndSetState(0, 1)) {
                setExclusiveOwnerThread(Thread.currentThread()); // 设置独占线程
                return true;
            }
            return false;
        }
        
        // 尝试释放锁
        @Override
        protected boolean tryRelease(int releases) {
            if (getState() == 0) 
                throw new IllegalMonitorStateException("锁未被当前线程持有");
            setExclusiveOwnerThread(null); // 清除独占线程
            setState(0); // 释放锁
            return true;
        }
        
        // 创建条件变量
        Condition newCondition() {
            return new ConditionObject();
        }
    }
    
    // Lock接口方法实现
    @Override
    public void lock() { 
        sync.acquire(1); 
    }
    
    @Override
    public boolean tryLock() { 
        return sync.tryAcquire(1); 
    }
    
    @Override
    public void unlock() { 
        sync.release(1); 
    }
    
    @Override
    public Condition newCondition() { 
        return sync.newCondition(); 
    }
    
    @Override
    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }
    
    @Override
    public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(timeout));
    }
}

4.2 CustomMutex使用示例

java 复制代码
package cn.tcmeta.aqs;

import java.util.concurrent.CountDownLatch;

/**
 * AQS自定义锁使用示例
 */
public class AQSExample {
    private final CustomMutex mutex = new CustomMutex();
    private int sharedResource = 0;
    
    public void demonstrateMutex() throws InterruptedException {
        // 创建多个线程竞争访问共享资源
        int threadCount = 5;
        CountDownLatch startLatch = new CountDownLatch(1);
        CountDownLatch endLatch = new CountDownLatch(threadCount);
        
        for (int i = 0; i < threadCount; i++) {
            final int threadId = i;
            new Thread(() -> {
                try {
                    startLatch.await(); // 等待开始信号
                    
                    // 使用自定义互斥锁保护临界区
                    mutex.lock();
                    try {
                        System.out.println("线程 " + threadId + " 获取锁,共享资源: " + sharedResource);
                        sharedResource++;
                        Thread.sleep(100); // 模拟工作
                    } finally {
                        mutex.unlock();
                    }
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                } finally {
                    endLatch.countDown();
                }
            }).start();
        }
        
        startLatch.countDown(); // 开始所有线程
        endLatch.await(); // 等待所有线程完成
        
        System.out.println("最终共享资源值: " + sharedResource);
    }
    
     static void main(String[] args) throws InterruptedException {
        AQSExample example = new AQSExample();
        example.demonstrateMutex();
    }
}

4.3 不可重入互斥锁(Mutex)

java 复制代码
package cn.tcmeta.aqs;

import java.util.concurrent.locks.AbstractQueuedSynchronizer;

/**
 * 基于 AQS 实现的不可重入互斥锁
 * state = 0: 未加锁, state = 1: 已加锁
 */
public class Mutex {
    private static class Sync extends AbstractQueuedSynchronizer {
        @Override
        protected boolean tryAcquire(int acquires) {
            // 仅当 state 为 0 时,通过 CAS 获取锁
            return compareAndSetState(0, 1);
        }

        @Override
        protected boolean tryRelease(int releases) {
            // 释放锁,设置 state 为 0
            setState(0);
            return true;
        }

        @Override
        protected boolean isHeldExclusively() {
            return getState() == 1;
        }
    }

    private final Sync sync = new Sync();

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

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

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

4.4 二元信号量(BinarySemaphore)

java 复制代码
package cn.tcmeta.aqs;

import java.util.concurrent.locks.AbstractQueuedSynchronizer;

/**
 * 二元信号量:只有 0 或 1 个许可
 */
public class BinarySemaphore {
    private static class Sync extends AbstractQueuedSynchronizer {
        Sync(int permits) {
            setState(permits); // 初始化许可数
        }

        @Override
        protected int tryAcquireShared(int acquires) {
            for (;;) {
                int available = getState();
                int remaining = available - acquires;
                if (remaining < 0 || compareAndSetState(available, remaining)) {
                    return remaining;
                }
            }
        }

        @Override
        protected boolean tryReleaseShared(int releases) {
            for (;;) {
                int current = getState();
                int next = current + releases;
                if (compareAndSetState(current, next)) {
                    return true;
                }
            }
        }
    }

    private final Sync sync;

    public BinarySemaphore(int permits) {
        if (permits < 0) throw new IllegalArgumentException();
        this.sync = new Sync(permits);
    }

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

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

4.5 自定义高级同步器

支持超时等待锁

java 复制代码
/**
 * 支持超时等待的自定义锁
 * 演示AQS高级用法
 */
public class TimeoutMutex implements Lock {
    private final Sync sync = new Sync();
    
    private static class Sync extends AbstractQueuedSynchronizer {
        @Override
        protected boolean tryAcquire(int acquires) {
            if (compareAndSetState(0, 1)) {
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }
        
        @Override
        protected boolean tryRelease(int releases) {
            if (getState() == 0) 
                throw new IllegalMonitorStateException();
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }
        
        // 添加超时获取方法
        public boolean tryAcquireNanos(int acquires, long nanosTimeout) 
            throws InterruptedException {
            return tryAcquire(acquires) || 
                   doAcquireNanos(acquires, nanosTimeout);
        }
    }
    
    @Override
    public void lock() {
        sync.acquire(1);
    }
    
    @Override
    public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(timeout));
    }
    
    // 其他方法实现...
}

五、AQS在JUC中的实际应用

5.1 ReentrantLock 中的 AQS 应用

java 复制代码
/**
 * ReentrantLock中AQS应用分析
 */
public class ReentrantLock implements Lock {
    private final Sync sync;
    
    abstract static class Sync extends AbstractQueuedSynchronizer {
        // 非公平锁尝试获取
        final boolean nonfairTryAcquire(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) throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }
        
        @Override
        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;
        }
    }
    
    // 非公平锁实现
    static final class NonfairSync extends Sync {
        @Override
        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
    }
    
    // 公平锁实现
    static final class FairSync extends Sync {
        @Override
        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;
        }
    }
}

5.2 CountDownLatch 中的 AQS 应用

java 复制代码
/**
 * CountDownLatch中AQS应用分析
 */
public class CountDownLatch {
    private static final class Sync extends AbstractQueuedSynchronizer {
        Sync(int count) {
            setState(count); // 初始化计数器
        }
        
        int getCount() {
            return getState();
        }
        
        // 共享模式尝试获取
        @Override
        protected int tryAcquireShared(int acquires) {
            return (getState() == 0) ? 1 : -1;
        }
        
        // 共享模式尝试释放
        @Override
        protected boolean tryReleaseShared(int releases) {
            for (;;) { // 自旋直到成功
                int c = getState();
                if (c == 0) return false; // 已经为0,不需要释放
                int nextc = c - 1;
                if (compareAndSetState(c, nextc)) // CAS更新状态
                    return nextc == 0; // 返回是否达到0
            }
        }
    }
    
    private final Sync sync;
    
    public CountDownLatch(int count) {
        if (count < 0) throw new IllegalArgumentException("count < 0");
        this.sync = new Sync(count);
    }
    
    public void await() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }
    
    public void countDown() {
        sync.releaseShared(1);
    }
}

六、AQS高级特性

6.1 条件变量(Condition)的实现

AQS 内部类ConditionObject实现了Condition接口,提供了类似Object.wait()/notify()的等待 / 通知机制,但更灵活(一个锁可关联多个条件队列)

  • ConditionObject 是 AQS 的内部类。
  • 每个 Condition 对应一个条件等待队列(单向链表)。
  • await():当前线程释放锁,加入条件队列,阻塞。
  • signal():将条件队列首节点转移到同步队列,等待获取锁。

线程调用 condition.await() 释放锁 加入条件队列 阻塞 signal() 转移节点到同步队列 线程被唤醒, 重新竞争锁

示例流程

  1. 线程获取锁后调用condition.await(),释放锁并进入条件队列;
  2. 其他线程调用condition.signal(),将条件队列的节点移至主队列;
  3. 主队列中的节点按规则竞争锁,获取锁后继续执行。

6.2 Condition示例

java 复制代码
/**
 * AQS条件变量使用示例
 */
public class ConditionExample {
    private final Lock lock = new ReentrantLock();
    private final Condition condition = lock.newCondition();
    private boolean conditionMet = false;
    
    public void awaitCondition() throws InterruptedException {
        lock.lock();
        try {
            while (!conditionMet) { // 条件检查,防止虚假唤醒
                System.out.println("条件未满足,线程进入等待...");
                condition.await(); // 释放锁并等待
            }
            // 条件满足,执行操作
            System.out.println("条件满足,继续执行...");
        } finally {
            lock.unlock();
        }
    }
    
    public void signalCondition() {
        lock.lock();
        try {
            conditionMet = true;
            System.out.println("条件已满足,唤醒等待线程...");
            condition.signal(); // 唤醒一个等待线程
        } finally {
            lock.unlock();
        }
    }
    
    public void signalAllCondition() {
        lock.lock();
        try {
            conditionMet = true;
            System.out.println("条件已满足,唤醒所有等待线程...");
            condition.signalAll(); // 唤醒所有等待线程
        } finally {
            lock.unlock();
        }
    }
}

七、AQS性能优化与最佳实践

7.1 最佳实践总结

  1. 正确实现模板方法
    • 确保 tryAcquire/tryRelease 等方法的线程安全性
    • 正确管理同步状态 (state)
  2. 合理选择同步模式
    • 独占模式:互斥访问资源(如锁)
    • 共享模式:多个线程可同时访问(如信号量)
  3. 避免常见陷阱
    • 正确处理中断
    • 避免死锁
    • 注意内存可见性
  4. 性能考虑
    • 减少不必要的 CAS 操作
    • 合理使用自旋等待
    • 考虑公平性 vs 吞吐量权衡

7.2 使用经验

✅ 正确使用

  • 优先使用标准同步器 :如 ReentrantLock,避免重复造轮子。

  • 钩子方法保持轻量 :避免在 tryAcquire 中执行复杂逻辑。

  • 正确处理中断 :在 acquireQueued 中检查中断状态。

  • 避免死锁 :确保 tryRelease 一定能成功释放

❌ 避免陷阱

  • 不要在持有锁时调用阻塞操作(如 I/O)。
  • 不要重写 AQS 的模板方法 (如 acquire),只重写钩子。
  • 避免在 tryRelease 中抛出异常,否则队列无法唤醒

八、总结AQS

AQS 的成功源于其分层设计思想

  • 底层:基于 CAS + volatile + LockSupport 实现无锁并发
  • 中层:CLH 队列管理线程排队
  • 上层:模板方法 + 钩子方法 提供扩展点

一句话总结

  • AQS 是 Java 并发的"操作系统内核"------它不直接提供服务,而是为构建锁、信号量、门闩等"进程"提供统一的调度、内存和中断机制。

AQS 是 Java 并发编程的基石,其通过状态变量(state)FIFO 等待队列模板方法模式,为同步工具的实现提供了统一框架。理解 AQS 的核心原理,不仅能帮助我们更好地使用 JDK 中的并发工具,还能在需要时自定义高效的同步器。

AQS 的设计体现了 "高内聚、低耦合" 的思想:将复杂的队列管理、线程阻塞 / 唤醒等通用逻辑封装在抽象类中,子类只需关注具体的同步规则。这种设计极大地降低了并发组件的开发难度,也保证了这些组件在性能和可靠性上的一致性。


✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅

往期资料:

链接: https://pan.baidu.com/s/13wJhUxSVY2pbWOgjuIzWtg 提取码: dhq8
点击获取往期资料合集

提取码: dhq8

✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅

相关推荐
孟婆来包棒棒糖~3 小时前
Maven快速入门
java·spring boot·spring·maven·intellij-idea
jingfeng5146 小时前
C++模板进阶
java·c++·算法
杨杨杨大侠6 小时前
附录 1:[特殊字符] Maven Central 发布完整指南:从零到成功部署
java·spring boot·maven
好学且牛逼的马6 小时前
GOLANG 接口
开发语言·golang
头发掉光的程序员6 小时前
第七章 利用Direct3D绘制几何体
c++·windows·图形渲染·direct12
ahauedu6 小时前
AI资深 Java 研发专家系统解析Java 中常见的 Queue实现类
java·开发语言·中间件
韭菜钟6 小时前
在Qt中用cmake实现类似pri文件的功能
开发语言·qt·系统架构
闲人编程6 小时前
Python第三方库IPFS-API使用详解:构建去中心化应用的完整指南
开发语言·python·去中心化·内存·寻址·存储·ipfs