并发编程-ReentrantLock解锁流程

并发编程之ReentrantLock解锁流程

目录

并发编程之ReentrantLock解锁流程

一、解锁流程

二、代码执行流程


一、解锁流程

情景:线程t1持有锁,t2在park。然后t1释放锁,唤醒t2

解锁之前AQS(NonfairSync)的状态。重点关注waitStatus的值和当前线程拥有者。

                                                                                       图1

解锁之后AQS(NonfairSync)的状态。

                                                                                    图2

二、代码执行流程

//1. ReentrantLock.java
public void unlock() {
    sync.release(1);
}

//2. ReentrantLock.java
/**
2.1 tryRelease(arg) 尝试释放锁
2.2 unparkSuccessor(h) 
2.3 LockSupport.unpark(s.thread); 会调用acquireQueued方法
*/
public final boolean release(int arg) {
    if (tryRelease(arg)) {
        //拿到当前头节点
        Node h = head;
        //h.waitStatus == -1 因为他需要唤醒t2线程。在t2线程入队的时候已经将它的前一个节点也就是head的waitStatus值设置为了-1
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h);
        return true;
    }
    return false;
}

protected final boolean tryRelease(int releases) {
    //当前状态值减1 c=0 (c不等于0的时候是重入,我们当前场景c一定等于0)
    int c = getState() - releases;
    if (Thread.currentThread() != getExclusiveOwnerThread())
        throw new IllegalMonitorStateException();
    boolean free = false;
    //c=0 条件成立
    if (c == 0) {
        free = true;
        //设置当前线程为空
        setExclusiveOwnerThread(null);
    }
    //设置当前状态为c=0
    setState(c);
    return free;
}
private void unparkSuccessor(Node node) {
    int ws = node.waitStatus;
    //ws == -1 将当前head的waitStatus值改为0 表示当前没有责任再去叫醒下一个节点。这里这么做是防止在并发情况下,别的线程也会去叫醒下一个节点
    if (ws < 0)
        compareAndSetWaitStatus(node, ws, 0);
    //拿到head的下一个节点 也就是t2线程
    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;
    }
    //会进入到 LockSupport.unpark(s.thread)方法
    if (s != null)
        LockSupport.unpark(s.thread);
}
final boolean acquireQueued(final Node node, int arg) {
    boolean failed = true;
    try {
        boolean interrupted = false;
        /**
           此时 自选加锁成功 在setHead()方法中将head节点从队列中出队。t2线程加锁成功
        */
        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);
    }
}

 


版权声明:本文为yibailiheng原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。