说到可重入锁,先从AQS的ConditionObject说起,AQS的内部类ConditionObject是构建显示锁条件队列的基础。之前AQS的没有说这个内部类,这里和ReentrantLock一起说一下。
1、AQS的内部类ConditionObject
addConditionWaiter方法的代码:
这个方法的作用是将当前线程封装好放到条件队列。
1 private Node addConditionWaiter() { 2 Node t = lastWaiter; 3 // If lastWaiter is cancelled, clean out. 4 if (t != null && t.waitStatus != Node.CONDITION) {//如果等待队列的最后一个是取消状态,就把遍历整个队列把所有取消状态的节点清除 5 unlinkCancelledWaiters(); 6 t = lastWaiter; 7 } 8 Node node = new Node(Thread.currentThread(), Node.CONDITION);//以当前线程新建一个节点 9 if (t == null)//根据条件将节点放入队列10 firstWaiter = node;11 else12 t.nextWaiter = node;13 lastWaiter = node;14 return node;//返回当前线程的节点15 }
doSignal方法的代码:
这个方法的作用就是唤醒当前线程。
1 private void doSignal(Node first) {2 do {3 if ( (firstWaiter = first.nextWaiter) == null)4 lastWaiter = null;5 first.nextWaiter = null;6 } while (!transferForSignal(first) &&//调用了transferForSignal方法7 (first = firstWaiter) != null);8 }
transferForSignal方法的代码:
1 final boolean transferForSignal(Node node) { 2 /* 3 * If cannot change waitStatus, the node has been cancelled. 4 */ 5 if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))//cas修改值,如果成功等待到了条件成立;如果失败节点的状态改为了CANCELLED,直接返回 6 return false; 7 8 /* 9 * Splice onto queue and try to set waitStatus of predecessor to10 * indicate that thread is (probably) waiting. If cancelled or11 * attempt to set waitStatus fails, wake up to resync (in which12 * case the waitStatus can be transiently and harmlessly wrong).13 */14 Node p = enq(node);//节点入队 这里可能会有点晕,这个节点不是刚从队列里取出吗,怎么又入队了 其实是因为队列不是同一个,每个ConditionObject对象都有一个条件队列,队列里的节点等待的条件成立了会被添加到AQS的队列,这时节点(线程)才有资格等待获取资源15 int ws = p.waitStatus;16 if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))//唤醒线程17 LockSupport.unpark(node.thread);18 return true;19 }
doSignalAll方法的代码:
这个方法的作用就是唤醒所有节点(线程)。
1 private void doSignalAll(Node first) {2 lastWaiter = firstWaiter = null;3 do {4 Node next = first.nextWaiter;5 first.nextWaiter = null;6 transferForSignal(first);7 first = next;8 } while (first != null);9 }
unlinkCancelledWaiters方法的代码:
这个方法被上面说的addConditionWaiter方法调用,将队列的取消状态的节点(线程)清除。
1 private void unlinkCancelledWaiters() { 2 Node t = firstWaiter; 3 Node trail = null; 4 while (t != null) { 5 Node next = t.nextWaiter; 6 if (t.waitStatus != Node.CONDITION) { 7 t.nextWaiter = null; 8 if (trail == null) 9 firstWaiter = next;10 else11 trail.nextWaiter = next;12 if (next == null)13 lastWaiter = trail;14 }15 else16 trail = t;17 t = next;18 }19 }
doSignal方法的代码:
1 public final void signal() {//唤醒一个节点(线程)2 if (!isHeldExclusively())3 throw new IllegalMonitorStateException();4 Node first = firstWaiter;5 if (first != null)6 doSignal(first);7 }
doSignalAll方法的代码:
1 public final void signalAll() {//唤醒所有节点2 if (!isHeldExclusively())3 throw new IllegalMonitorStateException();4 Node first = firstWaiter;5 if (first != null)6 doSignalAll(first);7 }
awaitUninterruptibly方法的代码:
这个方法的作用就是将节点(线程)放入条件队列。
1 public final void awaitUninterruptibly() { 2 Node node = addConditionWaiter();//放入条件队列 3 int savedState = fullyRelease(node);//释放资源 4 boolean interrupted = false; 5 while (!isOnSyncQueue(node)) {//当前节点是否在同步队列(在条件队列被唤醒后进入) 6 LockSupport.park(this);//如果不在,等待 7 if (Thread.interrupted())//检查是被中断还是被唤醒 8 interrupted = true;//如果是被中断设置interrupted,下面会设置中断标志 9 }10 if (acquireQueued(node, savedState) || interrupted)//尝试获取资源 设置中断标志11 selfInterrupt();12 }
await方法的代码:
await方法和awaitUninterruptibly方法很相似,不同的地方是中断的处理。await方法的节点()线程如果是中断结束等待的,会根据当前中断的处理模式判断是抛出异常还是保留中断标志,不会再尝试获取资源。
1 public final void await() throws InterruptedException { 2 if (Thread.interrupted()) 3 throw new InterruptedException(); 4 Node node = addConditionWaiter(); 5 int savedState = fullyRelease(node); 6 int interruptMode = 0; 7 while (!isOnSyncQueue(node)) { 8 LockSupport.park(this); 9 if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)//如果是中断,break10 break;11 }12 if (acquireQueued(node, savedState) && interruptMode != THROW_IE)13 interruptMode = REINTERRUPT;14 if (node.nextWaiter != null) // clean up if cancelled15 unlinkCancelledWaiters();16 if (interruptMode != 0)17 reportInterruptAfterWait(interruptMode);//抛出异常或保留中断标志18 }
ConditionObject的代码先说到这,下面说说ReentrantLock的代码。
2、ReentrantLock
ReentrantLock是独占模式的AQS,ReentrantLock有三个内部类,一个是抽象内部类。三个内部类为Sync、NonfairSync和FairSync。后面两个继承自前面一个。下面先说说这三个内部类。
Sync:
nonfairTryAcquire方法:
该方法的作用就是非公平地获取资源。
1 final boolean nonfairTryAcquire(int acquires) { 2 final Thread current = Thread.currentThread(); 3 int c = getState(); 4 if (c == 0) {//如果没有线程占有资源 5 if (compareAndSetState(0, acquires)) {//如果cas获取资源成功 6 setExclusiveOwnerThread(current);//将当前线程设置为独占资源的线程 7 return true; 8 } 9 }10 else if (current == getExclusiveOwnerThread()) {//如果当前线程是占有资源的线程11 int nextc = c + acquires;//增加state ReentrantLock里acquires都传1 state为n说明当前线程重入的次数为n - 112 if (nextc < 0)//溢出13 throw new Error("Maximum lock count exceeded");14 setState(nextc);//设置state值15 return true;16 }17 return false;18 }
tryRelease方法:
该方法的作用就是释放资源(锁),如果资源值(state)为0,则说明调用unlock的次数和调用lock的次数一样,锁可以释放供其它线程获取。
1 protected final boolean tryRelease(int releases) { 2 int c = getState() - releases; 3 if (Thread.currentThread() != getExclusiveOwnerThread())//如果当前线程不是独占占有资源的线程 4 throw new IllegalMonitorStateException();//抛出异常 5 boolean free = false; 6 if (c == 0) {//如果c等于0 资源全部释放(也就是释放了锁) 7 free = true; 8 setExclusiveOwnerThread(null); 9 }10 setState(c);//设置state的值11 return free;//返回是否释放了锁12 }
newCondition方法:
该方法的作用就是创建新的条件队列。
1 final ConditionObject newCondition() {2 return new ConditionObject();3 }
NonfairSync:
lock方法:
非公平获取锁,每个线程获取锁时都会先cas试一下,如果成功了就直接获取了锁,不用再从入队出队开始。
1 final void lock() {2 if (compareAndSetState(0, 1))3 setExclusiveOwnerThread(Thread.currentThread());4 else5 acquire(1);//如果不成功还要排队继续6 }
tryAcquire方法:
1 protected final boolean tryAcquire(int acquires) {2 return nonfairTryAcquire(acquires);3 }
FairSync:
lock方法:
公平获取锁,直接调用acquire,从入队出队开始。
final void lock() { acquire(1); }
tryAcquire方法:
tryAcquire方法和nonfairTryAcquire方法类似,主要区别在于tryAcquire要求获取资源的节点(线程)必须是队首节点。
protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) {//如果没有前驱节点(线程)且cas设置state成功,当前节点(线程)独占占有锁 setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; }
说完了内部类,再看看几个提供的方法。
1 public ReentrantLock() { 2 sync = new NonfairSync(); 3 } 4 5 public ReentrantLock(boolean fair) { 6 sync = fair ? new FairSync() : new NonfairSync(); 7 } 8 9 public void lock() {10 sync.lock();11 }12 13 public void lockInterruptibly() throws InterruptedException {14 sync.acquireInterruptibly(1);15 }16 17 public boolean tryLock() {18 return sync.nonfairTryAcquire(1);19 }20 21 public Condition newCondition() {22 return sync.newCondition();23 }
会发现这些方法基本上都是直接调用上面或之前说的那些方法。