1.大体流程
![在这里插入图片描述](https://img-blog.csdnimg.cn/6d6b7549f2904d4e9d233e61439a6bac.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5ZOm6LGB7pCL,size_20,color_FFFFFF,t_70,g_se,x_162.源码分析
(1)构造方法
默认是非公平锁,以下都默认使用非公平锁进行分析。
public ReentrantLock() {
sync = new NonfairSync();
}
也可通过参数调整决定使用公平锁还是非公平锁:
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
(2)lock()
lock的基本过程:
public void lock() {
sync.lock();
}
调用同步器的lock方法:不看同步队列是否还有线程再排队,直接尝试去获取锁(cas地修改state),修改成功直接设定当前线程为独占线程拥有者否则再次获取:
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
调用AQS同步器模板中的获取方法:
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
①tryAcquire(arg)
由重入锁定制的非公平锁:
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;//这就是重入锁的来历,如果当前线程是独占线程拥有者,说明这不是第一次进入。
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
如果sate为0,说明没有线程持有锁,获取成功后直接返回;如果当前线程就是独占线程拥有者,则重入次数+1。
如果获取失败,则准备进入同步队列排队等待。
先封装到Node,直接排队到队列尾部:
#为什么不再请求加入同步队列的时候再addWaiter呢?
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
Node pred = tail;
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
enq(node);
return node;
}
如果尾部为空,说明同步队列为空了,直接入队当head节点;如果有尾巴节点继续加在尾部,并返回其前继节点;
不过问题在于为什么还有可能队列非空,再次判断为节点呢?
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) { // Must initialize
if (compareAndSetHead(new Node()))
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
接下来就会请求进入同步队列:
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);
}
}
如果前继节点不是首节点,则应该找到一个状态为signal的前继节点作为前继节点:
也就是说允许前继节点状态为0,为什么呢?
其他情况,0和propagate状态
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
/*
* This node has already set status asking a release
* to signal it, so it can safely park.
*/
return true;
if (ws > 0) {
/*
* Predecessor was cancelled. Skip over predecessors and
* indicate retry.
*/
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);//也就是说允许前继节点状态为0,为什么呢?
pred.next = node;
} else {
/*
* waitStatus must be 0 or PROPAGATE. Indicate that we
* need a signal, but don't park yet. Caller will need to
* retry to make sure it cannot acquire before parking.
*/
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
前继节点为signal状态,保证挂起后能被前继节点唤醒,挂起线程:
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);//线程将暂停在这里!
return Thread.interrupted();// 返回中断标志并重置为false,不响应中断
}
假设线程挂起后,被其他线程修改了中断标志,那么此线程将被唤醒,修改interrupted为true。由于重置了线程的中断标志,将可以再次进入循环挂起。这就是不响应中断。
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;//此标记用于线程唤醒获取到锁后将线程中断标志还原(先前重置了中断标志位)
(3)unlock
调用同步器的release方法:
先尝试释放
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;
}
所谓的释放就是减去重入次数,如果重入次数为0,说明锁已经释放了;
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
此时当前线程还是头节点,修改当前节点的status为0,唤醒后继节点。唤醒后,被唤醒的线程将尝试获取锁,获取到锁后便成为新的头节点了。
情况1:为什么后继节点状态可能>0的?如果节点取消了或者是相应中断的节点会抛出异常,状态修改为1。比如说lockInterruptly() 方法就是相应中断的。
情况2:=0的节点不是signal状态,为啥会被唤醒?
节点进入同步队列的时候只对前继节点有要求,对本身节点的状态默认为0。而后加入的节点会将此节点置为-1,shouldParkAfterFailedAcquire方法中,compareAndSetWaitStatus(pred, ws, Node.SIGNAL);如果此节点是尾节点,没有后继节点将此节点的状态修改为-1,因此需要将状态为0的节点也唤醒。
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);
}
有几个问题值得思考:
#加入第一个获取锁的线程直接获取锁,后进的第一个线程成为头节点,谁来唤醒这个头节点呢?
在上面的唤醒方法里,这种情况会遍历队列,找到头节点唤醒;.
#头节点线程有几种状态?
第一个进来的头节点会被挂起,那唤醒后同样会p==head条件依然不成立,无法尝试获取锁啊??
private final boolean compareAndSetHead(Node update) {
return unsafe.compareAndSwapObject(this, headOffset, null, update);
}
(4)lockInterruptibly()
可响应中断的获取锁
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
AQS模板方法acquireInterruptibly(int arg)
public final void acquireInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (!tryAcquire(arg))
doAcquireInterruptibly(arg);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
没有获取到锁,于是调用doAcquireInterruptibly(arg)(AQS模板方法)
private void doAcquireInterruptibly(int arg)
throws InterruptedException {
final Node node = addWaiter(Node.EXCLUSIVE);
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
throw new InterruptedException();//响应中断
}
} finally {
if (failed)
cancelAcquire(node);//取消节点
}
}
取消节点:帮助后继节点寻找signal为-1的节点,并置空自身。如果是头节点就唤醒后继节点。
private void cancelAcquire(Node node) {
// Ignore if node doesn't exist
if (node == null)
return;
node.thread = null;
// Skip cancelled predecessors
Node pred = node.prev;
while (pred.waitStatus > 0)
node.prev = pred = pred.prev;
// predNext is the apparent node to unsplice. CASes below will
// fail if not, in which case, we lost race vs another cancel
// or signal, so no further action is necessary.
Node predNext = pred.next;
// Can use unconditional write instead of CAS here.
// After this atomic step, other Nodes can skip past us.
// Before, we are free of interference from other threads.
node.waitStatus = Node.CANCELLED;
// If we are the tail, remove ourselves.
if (node == tail && compareAndSetTail(node, pred)) {
compareAndSetNext(pred, predNext, null);
} else {
// If successor needs signal, try to set pred's next-link
// so it will get one. Otherwise wake it up to propagate.
int ws;
if (pred != head &&
((ws = pred.waitStatus) == Node.SIGNAL ||
(ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
pred.thread != null) {
Node next = node.next;
if (next != null && next.waitStatus <= 0)
compareAndSetNext(pred, predNext, next);
} else {
unparkSuccessor(node);
}
node.next = node; // help GC
}
}
取消的节点线程又会去哪里呢?
lockInterruptibly() throws InterruptedException ,向上抛异常,如果没有人处理线程就结束(不会影响其他线程);
(5) tryLock()
只是尝试获取,获取不到锁就做其他事,不会排队。
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
3.等待队列
增加一个等待队列,主要作用是替代sychonized的object.wati和sign方法的;并且一个同步队列可以增加多个不同的等待队列,大大的增强了灵活性;
可以参考以下模型:
无线挂起的
时间到自行唤醒的:
final ConditionObject newCondition() {
return new ConditionObject();
}
内部维护了一个头节点和尾节点的单向链表,添加节点时使用的是newWaiter(同步队列使用的next和prev);
private static final long serialVersionUID = 1173984872572414699L;
/** First node of condition queue. */
private transient Node firstWaiter;
/** Last node of condition queue. */
private transient Node lastWaiter;
另外两个常量
/*
* For interruptible waits, we need to track whether to throw
* InterruptedException, if interrupted while blocked on
* condition, versus reinterrupt current thread, if
* interrupted while blocked waiting to re-acquire.
*/
/** Mode meaning to reinterrupt on exit from wait */
private static final int REINTERRUPT = 1;
/** Mode meaning to throw InterruptedException on exit from wait */
private static final int THROW_IE = -1;
(1)await
挂起
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);
}
加入等待队列
private Node addConditionWaiter() {
Node t = lastWaiter;
// If lastWaiter is cancelled, clean out.
if (t != null && t.waitStatus != Node.CONDITION) {
unlinkCancelledWaiters();
t = lastWaiter;
}
Node node = new Node(Thread.currentThread(), Node.CONDITION);
if (t == null)
firstWaiter = node;
else
t.nextWaiter = node;
lastWaiter = node;
return node;
}
如果被正常唤醒(在挂起过程中未被中断),节点会加入到同步队列;
/**
* Checks for interrupt, returning THROW_IE if interrupted
* before signalled, REINTERRUPT if after signalled, or
* 0 if not interrupted.
*/
private int checkInterruptWhileWaiting(Node node) {
return Thread.interrupted() ?
(transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) :
0;
}
/**
* Transfers node, if necessary, to sync queue after a cancelled wait.
* Returns true if thread was cancelled before being signalled.
*
* @param node the node
* @return true if cancelled before the node was signalled
*/
final boolean transferAfterCancelledWait(Node node) {
if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) {
enq(node);//如果是再唤醒前就被中断,此时应该可以入队成功
return true;
}
/*
* If we lost out to a signal(), then we can't proceed
* until it finishes its enq(). Cancelling during an
* incomplete transfer is both rare and transient, so just
* spin.
*/
while (!isOnSyncQueue(node))//如果在唤醒之后中断,会返回false
Thread.yield();
return false;
}
否则,如果是再唤醒前中断的,需要抛出异常;
如果是唤醒后中断的,不需要抛出异常只需要修改中断标志;
/**
* Throws InterruptedException, reinterrupts current thread, or
* does nothing, depending on mode.
*/
private void reportInterruptAfterWait(int interruptMode)
throws InterruptedException {
if (interruptMode == THROW_IE)
throw new InterruptedException();
else if (interruptMode == REINTERRUPT)
selfInterrupt();
}
(2)signal
唤醒
public final void signal() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
Node first = firstWaiter;
if (first != null)
doSignal(first);
}
private void doSignal(Node first) {
do {
if ( (firstWaiter = first.nextWaiter) == null)
lastWaiter = null;
first.nextWaiter = null;
} while (!transferForSignal(first) &&
(first = firstWaiter) != null);
}
从等待队列加入到同步队列
Transfers a node from a condition queue onto sync queue
final boolean transferForSignal(Node node) {
/*
* If cannot change waitStatus, the node has been cancelled.
*/
if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
return false;
/*
* Splice onto queue and try to set waitStatus of predecessor to
* indicate that thread is (probably) waiting. If cancelled or
* attempt to set waitStatus fails, wake up to resync (in which
* case the waitStatus can be transiently and harmlessly wrong).
*/
Node p = enq(node);
int ws = p.waitStatus;
if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))//每次加入节点将前尾巴节点状态置为signal
LockSupport.unpark(node.thread);
return true;
}
加入到同步队列尾部,如果前继节点(同步队列的尾节点)被取消了且状态更改成功了,就唤醒当前线程;如果状态不大于0就直接唤醒线程;enq也就相当于只是加在了同步队列后面,并没有挂起或者请求的动作;
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) { // Must initialize
if (compareAndSetHead(new Node()))
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
唤醒后将在同步队列排队;