AQS-ReentrantLock.unlock 源码

    public void unlock() {
        sync.release(1);
    }
    public final boolean release(int arg) {
        if (tryRelease(arg)) { // 具体子类实现
            Node h = head; 
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }
// 1.1 非公平锁 尝试释放锁
protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false; // 释放是否锁
            if (c == 0) { // 若状态=0,该线程已全部执行完
                free = true; 
                setExclusiveOwnerThread(null);
            }
            setState(c); // 该线程仍然持有锁
            return free;
        }
// 
private void unparkSuccessor(Node node) {
        // 当前线程所在结点的状态
        int ws = node.waitStatus;
        if (ws < 0) // 如果状态<0。则将状态改为0
            compareAndSetWaitStatus(node, ws, 0);
		// 获取当前节点下一个节点
        Node s = node.next;
        // 若下个节点状态已经取消,则从尾节点依次向前找对当前节点最近的一个阻塞节点,然后唤醒该节点对应的线程【注意此处从尾节点开始向前找的见下面分析】
        if (s == null || s.waitStatus > 0) { 
            s = null;
            for (Node t = tail; t != null && t != node; t = t.prev)
                if (t.waitStatus <= 0)
                    s = t;
        }
        if (s != null)
            LockSupport.unpark(s.thread);
    }

当当前线程所在的节点的下个节点无效或者为空时,从尾节点开始向前找的原因:

  1. 线程A 执行完1,此时线程A所在的节点设置成了尾节点。此时发生线程切换
  2. 线程B 执行到1 也设置成了尾节点,且此时B的前驱节点为A。但A的next节点并没有指向B
  3. 此时再进行线程切换。线程C再执行unparkSuccessor 时,当前线程的next节点为A发现的next为空,但是此时A的下个节点是B。所以需要才从尾队列想前。
  4. 思考下🤔 如果把2 3 顺序兑换下 应该可以
 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; // 3
                if (compareAndSetTail(t, node)) { // 1
                    t.next = node;  // 2 
                    return t;
                }
            }
        }
    }

总结:

  1. tryRelease 当前状态值-1,若-1后状态值=0,则返回true,表示可以释释放资源
  2. 找到当前节点下一个阻塞的线程。unpark()唤醒该线程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值