下面我们看一下主要方法的调用关系,可以跟着我的 → 层级在脑海中大概过一遍每个方法的主要代码:
ReentrantLock#lock() ->ReentrantLock.FairSync#lock() // 公平模式获取锁 ->AbstractQueuedSynchronizer#acquire() // AQS的获取锁方法 ->ReentrantLock.FairSync#tryAcquire() // 尝试获取锁 ->AbstractQueuedSynchronizer#addWaiter() // 添加到队列 ->AbstractQueuedSynchronizer#enq() // 入队 ->AbstractQueuedSynchronizer#acquireQueued() // 里面有个for()循环,唤醒后再次尝试获取锁 ->AbstractQueuedSynchronizer#shouldParkAfterFailedAcquire() // 检查是否要阻塞 ->AbstractQueuedSynchronizer#parkAndCheckInterrupt() // 真正阻塞的地方获取锁的主要过程大致如下:
(1)尝试获取锁,如果获取到了就直接返回了;
(2)尝试获取锁失败,再调用addWaiter()构建新节点并把新节点入队;
(3)然后调用acquireQueued()再次尝试获取锁,如果成功了,直接返回;
(4)如果再次失败,再调用shouldParkAfterFailedAcquire()将节点的等待状态置为等待唤醒(SIGNAL);
(5)调用parkAndCheckInterrupt()阻塞当前线程;
(6)如果被唤醒了,会继续在acquireQueued()的for()循环再次尝试获取锁,如果成功了就返回;
(7)如果不成功,再次阻塞,重复(3)(4)(5)直到成功获取到锁。