ReentrantLock底层实现 小结

来源:互联网 发布:淘宝退货调包闪电退款 编辑:程序博客网 时间:2024/05/16 06:34

1. FairSync 的 state & tail & head

tail:尾节点, 链表

head:头节点, 链表

state:锁状态

简单来说

lock()

1). 看看state状态,合适就拿着state直接开跑

2). 不合适就在把自己放在head链表最后

3). 首先找到自己前一个状态合格的哥们,如果前面哥们的状态是CANCELLED,那需要把这哥们从head链表中剔除掉,然后知道依次向前找到一个状态合格的哥们

4). 把找到的哥们状态置为SIGNAL,然后自己就去安心睡觉(LockSupport.park)

(最前排的哥们叫”哨兵节点“,“哑节点”)

    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);        }    }
unlock()
1). 把state-1看看,如果>0那不好意思哥们我仍然持有当前锁,如果==0那么就把state=0

2). 然后检查链表里的头个Node状态是非CANCELLED时,则把头节点后面的兄弟拿出来叫醒(LockSupport.unpark)


lockInterruptibly()

1). 当前线程处于LockSupport.park时,可以被interrept和unlock唤醒。lockInterruptibly()处理interrept是及时throw new InterruptedException(),而lock()只是标记一下,直到拿到锁才会Thread.currentThread().interrupt()


2. Condition firstWaiter & lastWaiter(只有持有锁的线程才有资格await(), signal()。否则抛出java.lang.IllegalMonitorStateException)

await()

1). 创建当前线程对应的Node并放入firstWaiter

2). 把当前线程持有的Lock全部释放(<=>特殊的unlock)

3). 然后从FairSync 的的链表中找出第二个节点进行LockSupport.unpark

4). 停下自己,LockSupport.park(this)

        public final void await() throws InterruptedException {            if (Thread.interrupted())                throw new InterruptedException();            Node node = addConditionWaiter();            int savedState = fullyRelease(node);            int interruptMode = 0;            while (!isOnSyncQueue(node)) {                LockSupport.park(this);                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)                    break;            }            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)                interruptMode = REINTERRUPT;            if (node.nextWaiter != null) // clean up if cancelled                unlinkCancelledWaiters();            if (interruptMode != 0)                reportInterruptAfterWait(interruptMode);        }
signal()
1) 从firstWaiter链表中拿出第一个然后放到head链表最后