在调用到ReentrantLock的unlock方法的时候,无论公平锁与非公平锁都会调用到sync.release(1)
方法。
Sync.release方法解析
该方法注释为
/**
* Releases in exclusive mode. Implemented by unblocking one or
* more threads if {@link #tryRelease} returns true.
* This method can be used to implement method {@link Lock#unlock}.
*
* @param arg the release argument. This value is conveyed to
* {@link #tryRelease} but is otherwise uninterpreted and
* can represent anything you like.
* @return the value returned from {@link #tryRelease}
*/
从一个独占的模式中退出。如果tryRelease
方法返回true的话,则通过unblock一个或者多个线程来实现。这个方法通常用来实现Lock.unlock函数。
而代码如下
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
调用tryRelease
方法,如果返回true的话,说明解锁成功,那么则会将当前的head
节点进行解锁,接着判断waitStatus
不为0,说明当前头节点处于非运行状态,则会调用unparkSuccessor
,将头节点传入,而头节点的Thread也因此被唤醒。
tryRelease方法解析
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
- 判断当前的线程是否是占用锁的线程,如果不是的话,那么抛出非法异常
- 否则的话,则判断减少
releases
之后的值是否为0,如果为0的话,说明目前锁都已经被释放了,则free标识为true,说明当前锁处于空闲状态,并且将当前锁占有线程置空 - 设置当前的锁状态,并且返回当前锁是否是空闲的
unparkSuccessor解析
该方法的作用是唤醒一个这个节点的后继,也就是head->next。
private void unparkSuccessor(Node node) {
/*
* If status is negative (i.e., possibly needing signal) try
* to clear in anticipation of signalling. It is OK if this
* fails or if status is changed by waiting thread.
*/
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
/*
* Thread to unpark is held in successor, which is normally
* just the next node. But if cancelled or apparently null,
* traverse backwards from tail to find the actual
* non-cancelled successor.
*/
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);
}
- 首先判断当前节点的
waitStatus
是否小于0,如果小于0的话,说明当前的状态都是SINGNAL
等状态,则通过CAS操作将当前节点的ws
变量清空 - 获取当前节点的next节点,如果next节点为空或者
waitStatus
大于0的话,那么说明next节点不合法,则会从后往前遍历,找到最前面一个waitStatus<=0
的节点,只有这种节点的线程代表着被阻塞了,那么则调用LockSupport.unpark(s.thread)
将该节点阻塞的线程释放,继续执行。
网友评论