AQS --》AbstractQueuedSynchronizer[后续在不断补充]

AbstractQueuedSynchronizer

最后看一下抽象类 AbstractQueuedSynchronizer,在同步组件的实现中,AQS 是核心部分,同步组件的实现者通过使用 AQS 提供的模板方法实现同步组件语义,AQS 则实现了对同步状态的管理,以及对阻塞线程进行排队,等待通知等等一些底层的实现处理。AQS 的核心包括:同步队列,独占式锁的获取和释放,共享锁的获取和释放以及可中断锁,超时等待锁获取这些特性的实现,而这些实际上则是 AQS 提供出来的模板方法。源码如下。

public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer
    implements java.io.Serializable {

    /**
     * 当共享资源被某个线程占有,其他请求该资源的线程将会阻塞,从而进入同步队列。
     * 就数据结构而言,队列的实现方式无外乎两者一是通过数组的形式,另外一种则是链表的形式。
     * AQS中的同步队列则是通过链式方式进行实现,下面的内部类Node便是其实现的载体
     */
    static final class Node {

        /** Marker to indicate a node is waiting in shared mode */
        static final Node SHARED = new Node();
        /** Marker to indicate a node is waiting in exclusive mode */
        static final Node EXCLUSIVE = null;

        // 节点从同步队列中取消
        static final int CANCELLED =  1;
        // 后继节点的线程处于等待状态,如果当前节点释放同步状态会通知后继节点,
        // 使得后继节点的线程能够运行;
        static final int SIGNAL    = -1;
        // 当前节点进入等待队列中
        static final int CONDITION = -2;
        // 表示下一次共享式同步状态获取将会无条件传播下去
        static final int PROPAGATE = -3;

        // 节点状态
        volatile int waitStatus;

        // 当前节点/线程的前驱节点
        volatile Node prev;

        // 当前节点/线程的后驱节点
        volatile Node next;

        // 加入同步队列的线程引用
        volatile Thread thread;

        // 等待队列中的下一个节点
        Node nextWaiter;

        final boolean isShared() {
            return nextWaiter == SHARED;
        }

        final Node predecessor() throws NullPointerException {
            Node p = prev;
            if (p == null)
                throw new NullPointerException();
            else
                return p;
        }

        Node() {    // Used to establish initial head or SHARED marker
        }

        Node(Thread thread, Node mode) {     // Used by addWaiter
            this.nextWaiter = mode;
            this.thread = thread;
        }

        Node(Thread thread, int waitStatus) { // Used by Condition
            this.waitStatus = waitStatus;
            this.thread = thread;
        }
    }

    /**
     * AQS实际上通过头尾指针来管理同步队列,同时实现包括获取锁失败的线程进行入队,
     * 释放锁时对同步队列中的线程进行通知等核心方法。
     */
    private transient volatile Node head;
    private transient volatile Node tail;

    /**
     * 获取独占式锁
     */
    public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

    /**
     * 释放独占式锁
     */
    public final boolean release(int arg) {
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

    /**
     * 获取可中断式锁
     */
    public final void acquireInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        if (!tryAcquire(arg))
            doAcquireInterruptibly(arg);
    }

    /**
     * 获取共享锁
     */
    public final void acquireShared(int arg) {
        if (tryAcquireShared(arg) < 0)
            doAcquireShared(arg);
    }

    /**
     * 释放共享锁
     */
    public final boolean releaseShared(int arg) {
        if (tryReleaseShared(arg)) {
            doReleaseShared();
            return true;
        }
        return false;
    }
}

J.U.C 中许多锁和并发工具类的核心实现都依赖于 AQS,如:ReentrantLock、ReentrantReadWriteLock、Semaphore、CountDownLatch 等。

AQS 的源码中 方法很多,但主要做了三件事情:
1:管理 同步状态;
2 维护 同步队列;
3 阻塞和唤醒 线程
从行为上来区分就是 获取锁 和 释放锁,从模式上来区分就是 独占锁 和 共享锁。

实现原理

AQS 内部维护了一个 FIFO 队列来管理锁。线程首先会尝试获取锁,如果失败,则将当前线程以及等待状态等信息包成一个 Node 节点放入同步队列阻塞起来,当持有锁的线程释放锁时,就会唤醒队列中的后继线程。
伪代码

-------------------------------         ###    获取锁
`·while (不满足获取锁的条件) {
    把当前线程包装成节点插入同步队列
    if (需要阻塞当前线程)
        阻塞当前线程直至被唤醒
}
将当前线程从同步队列中移除`
 ---------------------------           ### 释放锁
修改同步状态
if (修改后的状态允许其他线程获取到锁)
    唤醒后继线程

AQS 最主要的就是Unsafe和LockSupport

LockSupport的介绍

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值