java AbstractQueuedSynchronizer探索

AbstractQueuedSynchronizer是jdk中绝大部分Lock接口实现类的一个基础抽象类,它依赖的类很少,再往深里挖也只剩下Unsafe类了,虽然本身代码量也不是很多,但足以称得起AQS框架的大名,像ReentrantLock、CountDownLatch等这类易用的工具类都是对AbstractQueuedSynchronizer进行了简单的封装,因此想要学好java并发充分理解AbstractQueuedSynchronizer类是必不可少的

API说明

依赖AbstractQueuedSynchronizer实现同步器时通常要自己实现下面几个方法才行,直接调用AbstractQueuedSynchronizer的这几个方法会抛出UnsupportedOperationException异常

方法名称描述
boolean tryAcquire(int arg)排它的获取这个状态。这个方法的实现需要查询当前状态是否允许获取,然后再进行获取(使用compareAndSetState来做)状态。
tryRelease(int arg)释放状态。
int tryAcquireShared(int arg)共享的模式下获取状态。
tryReleaseShared(int arg)共享的模式下释放状态。
boolean isHeldExclusively()在排它模式下,状态是否被占用。

AbstractQueuedSynchronizer的结构如下,主要由ConditionObject、Node以及一堆私有方法组成,大部分重要方法只能由他本身调用或者子类调用
在这里插入图片描述
在这里插入图片描述
直接继承AbstractQueuedSynchronizer的类主要有下面几个
ReentrantLock.Sync 公平锁与非公平锁
ReentrantReadWriteLock.Sync 读锁与写锁
Semaphore.Sync 信号量控制
ThreadPoolExecutor.Worker 信号量控制

关键方法解析:
addWaiter(Node)

    private Node addWaiter(Node mode) {
    //创建一个新节点,保存当前线程
        Node node = new Node(Thread.currentThread(), mode);
        //队列尾结点不为空 则设置新节点为尾结点,快速入队
        Node pred = tail;
        if (pred != null) {
            node.prev = pred;
            //尾结点没变时可快速入队,若是此刻尾结点被其他线程改变则只能通过enq方法补救,再次入队
            if (compareAndSetTail(pred, node)) {
                pred.next = node;
                return node;
            }
        }
        //旧尾结点为空或者是新尾结点设置失败的补救措施
        enq(node);
        return node;
    }

enq() addWaiter方法快速入队失败后通过本方法再次入队

    private Node enq(final Node node) {
        for (;;) {
            Node t = tail;
            if (t == null) { // Must initialize
                //尾结点为空则设置一个新头结点,并将尾结点也指向它,即使两个线程同时设置了一个新节点,在进行cas比较的时候也会失败,因为compareAndSetHead方法是有旧头节点为null时才能赋值成功
                if (compareAndSetHead(new Node()))
                    tail = head;
            } else {
                //此刻head肯定不为空,故队列中的有效节点的前置节点一定不为空,Node的获取前置节点为空时会抛异常,
            	//尾结点不为空,则将node设置为尾结点(cas执行)
                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)
            /*
             * pred节点处于发信号状态,返回true
             */
            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;
    }

parkAndCheckInterrupt 阻塞线程 检查中断状态

 private final boolean parkAndCheckInterrupt() {
 	//阻塞当前线程
        LockSupport.park(this);
        return Thread.interrupted();
    }

cancelAcquire 取消获取到的信号量

private void cancelAcquire(Node node) {
        // Ignore if node doesn't exist
        if (node == null)
            return;

        node.thread = null;

        // Skip cancelled predecessors
        Node pred = node.prev;
        while (pred.waitStatus > 0)
            node.prev = pred = pred.prev;

        // predNext is the apparent node to unsplice. CASes below will
        // fail if not, in which case, we lost race vs another cancel
        // or signal, so no further action is necessary.
        Node predNext = pred.next;

        // Can use unconditional write instead of CAS here.
        // After this atomic step, other Nodes can skip past us.
        // Before, we are free of interference from other threads.
        node.waitStatus = Node.CANCELLED;

        // If we are the tail, remove ourselves.
        if (node == tail && compareAndSetTail(node, pred)) {
            compareAndSetNext(pred, predNext, null);
        } else {
            // If successor needs signal, try to set pred's next-link
            // so it will get one. Otherwise wake it up to propagate.
            int ws;
            if (pred != head &&
                ((ws = pred.waitStatus) == Node.SIGNAL ||
                 (ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
                pred.thread != null) {
                Node next = node.next;
                if (next != null && next.waitStatus <= 0)
                    compareAndSetNext(pred, predNext, next);
            } else {
                unparkSuccessor(node);
            }

            node.next = node; // help GC
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值