RenntrantLock中unlock过程解析
1 | public static void main(String[] args) { |
直接点进unlock方法,这个解锁和加锁不一样不分公平非公平之说。
1 | public void unlock() { |
查看release方法
release方法
1 | public final boolean release(int arg) { |
/** * h != null 判断队列头是否为空,如果head执行null,说明当前并没发生竞争,只有一个线程访问或者线程交替访问简短来说就是发生线程竞争的情况 * h.waitStatus != 0 需要满足这个条件是因为如果头线程的waitStatus为0的话只能说明线程中曾发生过竞争,但是现在已经不存在需要唤醒的结点了,就是当前线程中只有头结点这一个结点。 * 你不了解为什么这样的话可以看加锁的过程,后一个结点会把前一个结点的状态设置为-1。然后再根据后面说明的唤醒线程的具体处理过程unparkSuccessor(h)方法看一看。 */
先看tryRelease这个方法,这个和加锁中的那个tryAcquire方法一样的,一个尝试解锁,一个尝试获取锁。都是模板方法的体现,具体的实现交由子类重写。

tryRelease方法
1 | protected final boolean tryRelease(int releases) { |
1 | protected final void setExclusiveOwnerThread(Thread thread) { |
这个方法只是简单的释放锁而已并不是释放锁的重头戏,唤醒线程释放锁才是重头戏。这个tryRelease方法也体现了ReentrantLock锁的重入性。
这个方法执行完毕后返回free,如果释放成功,返回true,看release方法接着向下执行。
unparkSuccessor方法(※)
1 | private void unparkSuccessor(Node node) { |

线程被唤醒之后
不知道还知不知道这个被唤醒的线程当时最后被阻塞哪里!!!
1 | private final boolean parkAndCheckInterrupt() { |
被唤醒的那个线程当时被阻塞到了这里,被唤醒之后肯定要尝试获取锁,走的还是加锁的那套流程,知道在哪阻塞了加锁之前那套也说的很明白。可以看之前的加锁过程来了解,这里简单的说明。

return Thread.interrupted();这个返回值不用太在意,返回线程的一个中断状态,阻塞的时候是否被中断了,这里很细节暂时不用管。只知道返回了true或者false,程序继续执行,又进入一次for循环,因为锁已经是空闲状态所有,这里尝试获取锁会成功,然后将原来的头结点干掉,当前节点变为原来的头结点。
这也就说明了unparkSuccessor中为什么直接ws设置为0,这个当前节点也有两种情况。
一种为<0,说明线程中还存在需要被唤醒的结点,它释放锁后和这个unlock路线一样的。
还有一种情况是状态为0,说明当前节点是这个队列中最后的那个结点(因为最后那个结点的状态才会是0),队列中也自然就不存在需要被唤醒的结点了啊。
总结
解锁过程就是将这个锁的状态设置为0->将当前持有锁的线程设置为null->唤醒队列中的线程->被唤醒的线程执行加锁的过程。。。。明白了加锁过程解锁应该很简单。



