AQS详解

谈谈你对AQS的理解:

AQS 的全称为 **AbstractQueuedSynchronizer** ,翻译过来的意思就是抽象队列同步器。这个类在 java.util.concurrent.locks 包下面。AQS 为构建锁和同步器提供了一些通用功能的实现,因此,使用 AQS 能简单且高效地构造出应用广泛的大量的同步器,比如我们提到的 ReentrantLockSemaphore,其他的诸如 ReentrantReadWriteLockSynchronousQueue等等皆是基于 AQS 的。

原理:

AQS 核心思想是,如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,那么就需要一套线程阻塞等待以及被唤醒时锁分配的机制。因此aqs中有一个链表实现的阻塞队列,并将线程封装成队列的结点,头结点是拿到了锁的线程节点。因此释放锁时,会唤醒头结点之后的第一个有效结点。

锁的状态用了status的int变量表示,0表示无锁,1为有锁,大于1则是锁重入的次数,释放锁之后,stats的值应该是0.

并且AQS是利用了Volatile和CAS实现多线程抢锁,state,head,tail都是用volatile修辞的变量,比如尾插节点的时候,修改state变量的时候需要用到AQS。

AQS不仅可以实现互斥锁还可以实现共享锁。AQS采用的是模版方法设计模式,如果实现互斥锁则需要重写tryaquire,tryrelease,如果实现共享锁,则需要重写tryaquire_shared和tryrelease。

AQS还提供了条件变量,也就是允许线程在满足某些条件之前等待,并且在其他线程满足条件时唤醒等待这个条件的线程,并且还维护了一个条件队列,当唤醒等待条件的线程时,修改线程节点的状态为可唤醒状态,然后将等待队列中的节点从条件等待队列中转移到同步队列中,以便被唤醒后能够获得锁。

在这里插入图片描述

5.同步器

原理解读

模板方法设计模式,如何抢锁和释放锁由子类实现。

从获取锁的逻辑开始:

acquire方法
public final void acquire(int arg) {
    // 如果获取不到锁,则先把该线程结点加入到阻塞队列中,(互斥锁)
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}
addWaiter方法
private Node addWaiter(Node mode) {
    Node node = new Node(Thread.currentThread(), mode);
    // Try the fast path of enq; backup to full enq on failure
    Node pred = tail;
    if (pred != null) {
        // 可能有很多个线程竞争在一个队列的坑位,
        // 那么先把你们的前驱都指向尾节点,线程通过CAS竞争,让tail的next的指向自己。
        node.prev = pred;
        // CAS设置尾结点
        if (compareAndSetTail(pred, node)) {
            // 竞争到了,直接返回自己
            pred.next = node;
            return node;
        }
    }
    // 没有竞争到的,就继续循环竞争
    enq(node);
    return node;
}
enq方法
private Node enq(final Node node) {
    for (;;) {
        Node t = tail;
        // 有可能前一个已经竞争到了,但是有释放掉了。要做初始化
        if (t == null) { // Must initialize
            if (compareAndSetHead(new Node()))
                tail = head;
        } else {
            // 当前线程继续竞争,重复,循环,直到竞争成功
            node.prev = t;
            if (compareAndSetTail(t, node)) {
                t.next = node;
                return t;
            }
        }
    }
}
acquireQueued方法
final boolean acquireQueued(final Node node, int arg) {
    boolean failed = true;
    try {
        boolean interrupted = false;
        for (;;) {
            // 获取前驱节点
            final Node p = node.predecessor();
            // 如果你是第一节点,那是不是你可以尝试获取锁
            if (p == head && tryAcquire(arg)) {
                setHead(node);
                p.next = null; // help GC
                failed = false;
                return interrupted;
            }
            // 如果获取不到,阻塞自己,但是前提是你前面的结点是有效的结点。
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                interrupted = true;
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}
shouldParkAfterFailedAcquire方法
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
    int ws = pred.waitStatus;
    if (ws == Node.SIGNAL)
  		// 有效,就返回
        return true;
    if (ws > 0) {
  		// 无效,找到第一个有效的
        do {
            node.prev = pred = pred.prev;
        } while (pred.waitStatus > 0);
        pred.next = node;
    } else {
		
        compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
    }
    return false;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

zhou吗

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

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

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

打赏作者

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

抵扣说明:

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

余额充值