AQS介绍

AQS(AbstractQueuedSynchronizer)是Java并发包中的一个核心抽象类,它定义了一套多线程访问共享资源的同步框架。

核心机制

AQS通过一个volatile int类型的state成员变量来表示同步状态,其具体语义由子类定义,例如在独占锁中,state为0表示资源未被持有,大于0则表示被持有且可能记录重入次数。当线程尝试获取资源失败时,AQS会将其封装成一个Node节点,并通过内置的FIFO双向链表(一种变种的CLH队列)来管理这些等待线程。

工作原理

在这里插入图片描述

线程首先通过CAS操作尝试修改state以获取资源。如果成功,线程将独占资源;如果失败,AQS会将当前线程加入等待队列并可能将其挂起。当占有资源的线程释放资源(通常是state减到0)时,它会唤醒队列中的后继线程,使其重新尝试获取资源。

资源共享模式

AQS支持两种主要的资源共享模式:

  • 独占模式:一次只有一个线程能获取到同步状态,例如ReentrantLock。
  • 共享模式:多个线程可以同时获取同步状态,例如CountDownLatch和Semaphore。

AQS使用

AQS使用了模版方法模式,如果需要自定义同步器,通常按以下步骤进行使用:

  1. 使用者继承AbstractQueuedSynchronizer并重写指定的方法。
  2. 在自定义的同步组件方法中,调用AQS中的模版方法(如public变量修饰的方法),这些模版方法会调用使用者重写的方法。

AQS使用了模版方法模式,自定义同步器时需要重写下面几个AQS提供的模版方法

isHeldExclusively()//该线程是否正在独占资源。
tryAcquire(int)//独占方式。尝试获取资源,成功则返回true,失败则返回false。
tryRelease(int)//独占方式。尝试释放资源,成功则返回true,失败则返回false。
tryAcquireShared(int)//共享方式。尝试获取资源。负数表示失败;0表示成功,但没有剩余可用资源;正数表示成功,且有剩余资源。
tryReleaseShared(int)//共享方式。尝试释放资源,成功则返回true,失败则返回false。

默认情况下,每个方法都抛出UnsupportedOperationException。这些方法实现必须是内部线程安全的,并且通常应该简短而不是阻塞。

例子

按照上述AQS的使用步骤,来看一下ReentrantLock的实现。

  1. 步骤一:使用者继承AbstractQueuedSynchronizer并重写指定的方法。
  • 在ReentrantLock类实现内部,Sync 重写 了AbstractQueuedSynchronizer类中的 模版方法 tryRelease和isHeldExclusively方法。
    abstract static class Sync extends AbstractQueuedSynchronizer {
            private static final long serialVersionUID = -5179523762034025860L;
            abstract void lock();
    
            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) // overflow
                        throw new Error("Maximum lock count exceeded");
                    setState(nextc);
                    return true;
                }
                return false;
            }
    
            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;
            }
    
            protected final boolean isHeldExclusively() {
                return getExclusiveOwnerThread() == Thread.currentThread();
            }
            ......   
        }
    
    非公平锁同步类,NonfairSync类继承了Sync并重写了AbstractQueuedSynchronizer中的tryAcquire方法。
    static final class NonfairSync extends Sync {
            private static final long serialVersionUID = 7316153563782823691L;
            final void lock() {
                if (compareAndSetState(0, 1))
                    setExclusiveOwnerThread(Thread.currentThread());
                else
                    acquire(1);
            }
    
            protected final boolean tryAcquire(int acquires) {
                return nonfairTryAcquire(acquires);
            }
        }
    
  1. 步骤二:在自定义的同步组件方法中,调用AQS中的模版方法,这些模版方法会调用使用者重写的方法。
  • 在ReentrantLock中,对外提供了lock()方法进行加锁。public void lock() { sync.lock(); }。sync默认是非公平锁对象,lock()具体实现如上NonfairSync类中所示,lock()实现中调用了 模版方法 compareAndSetState和acquire方法。
    public final void acquire(int arg) {
            if (!tryAcquire(arg) &&
                acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
                selfInterrupt();
        }
    
    其中acquire方法调用了NonfairSync中重写的tryAcquire方法。

参考:https://cloud.tencent.com/developer/article/1953957

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

菜鸡儿齐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值