本文紧接上文的AQS源码,如果对于ReentrantLock没有基础可以先阅读我的上一篇文章学习ReentrantLock的源码
重入加锁其实就是将AQS的state进行加一操作
然后释放锁资源将AQS的state进行减一操作
当state为0时才会彻底的释放锁资源
在ReentrantLock中可打断就是在等待锁的过程中可以被interrupt打断(需要调用lockInterruptibly),lock方法设置了打断标记,但是只有在线程获得锁的时候才能知道自己有没有在阻塞的过程中有没有被打断。
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())// 我们这边会检查打断,如果打断的话返Thread.interrupted() interrupted = true; // 这里将打断标记置为true后,继续进入循环。直到获得到锁返回标记 } } finally { if (failed) cancelAcquire(node); } }
首先我们需要调用加锁的lockInterruptibly()方法
public void lockInterruptibly() throws InterruptedException { sync.acquireInterruptibly(1); }
可打断主要原因在如下代码解释。用异常代替了返回标记,让线程可以直接再park的过程中直接结束
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(); // 再被打断的时候不会将其标记置为true,而是直接抛出一个异常,打断当前的等待。 } } finally { if (failed) cancelAcquire(node); } }
Condition是一个接口,实际上是ReentrantLock的ConditionObject类作为其实现类。
首先我们创建一个condition就会调用其构造方法。其实就是产生一个新的conditionObject
final ConditionObject newCondition() { return new ConditionObject(); }
接下来,简单剖析一个源码
public final void await() throws InterruptedException { if (Thread.interrupted()) // 如果被打断,抛异常 throw new InterruptedException(); Node node = addConditionWaiter(); // 1.向AQS中添加一个等待链表的node 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(); // 这个和阻塞队列相似不过是全部遍历,清除不在等待队列上的node t = lastWaiter; } Node node = new Node(Thread.currentThread(), Node.CONDITION); if (t == null) // 添加到waitting尾部 firstWaiter = node; else t.nextWaiter = node; lastWaiter = node; return node; }
signal唤醒源码,简单介绍就是直接将等待的firstWaiter指向的等待链表的第一个进行解除阻塞,然后将其放入阻塞链表中。不过多赘述。
public final void signal() { if (!isHeldExclusively()) throw new IllegalMonitorStateException(); Node first = firstWaiter; if (first != null) doSignal(first); }