Board logo

标题: Java并发编程-AbstractQueuedSynchronizer源码分析(6) [打印本页]

作者: look_w    时间: 2019-1-17 19:25     标题: Java并发编程-AbstractQueuedSynchronizer源码分析(6)

public final boolean release(int arg)在unlock方法的实现中,使用了同步器的release方法。相对于在之前的acquire方法中可以得出调用acquire,保证能够获取到锁(成功获取状态),而release则表示将状态设置回去,也就是将资源释放,或者说将锁释放。
[url=][/url]
1    public final boolean release(int arg) {2        if (tryRelease(arg)) {3            Node h = head;4            if (h != null && h.waitStatus != 0)5                unparkSuccessor(h);6            return true;7        }8        return false;9    }[url=][/url]




上述逻辑主要包括:
1. 尝试释放状态;
tryRelease能够保证原子化的将状态设置回去,当然需要使用compareAndSet来保证。如果释放状态成功过之后,将会进入后继节点的唤醒过程。
2. 唤醒当前节点的后继节点所包含的线程。
通过LockSupport的unpark方法将休眠中的线程唤醒,让其继续acquire状态。
[url=][/url]
01    private void unparkSuccessor(Node node) {02        // 将状态设置为同步状态03        int ws = node.waitStatus;04        if (ws < 0)      compareAndSetWaitStatus(node, ws, 0);   // 获取当前节点的后继节点,如果满足状态,那么进行唤醒操作  

                                                                      // 如果没有满足状态,从尾部开始找寻符合要求的节点并将其唤醒     Node s = node.next;     if (s == null || s.waitStatus > 0) {05            s = null;06            for (Node t = tail; t != null && t != node; t = t.prev)07                if (t.waitStatus <= 0)08                    s = t;09            }10        if (s != null)11            LockSupport.unpark(s.thread);12    }[url=][/url]


上述逻辑主要包括,该方法取出了当前节点的next引用,然后对其线程(Node)进行了唤醒,这时就只有一个或合理个数的线程被唤醒,被唤醒的线程继续进行对资源的获取与争夺。
回顾整个资源的获取和释放过程:
在获取时,维护了一个sync队列,每个节点都是一个线程在进行自旋,而依据就是自己是否是首节点的后继并且能够获取资源;
在释放时,仅仅需要将资源还回去,然后通知一下后继节点并将其唤醒。
这里需要注意,队列的维护(首节点的更换)是依靠消费者(获取时)来完成的,也就是说在满足了自旋退出的条件时的一刻,这个节点就会被设置成为首节点。
protected boolean tryAcquire(int arg)tryAcquire是自定义同步器需要实现的方法,也就是自定义同步器非阻塞原子化的获取状态,如果锁该方法一般用于Lock的tryLock实现中,这个特性是synchronized无法提供的。




欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/) Powered by Discuz! 7.0.0