上篇文章讲了ReentrantLock的加锁和释放锁的使用,这篇文章是对ReentrantLock的补充.ReentrantLock # newCondition()可以创建条件,在ReentrantLock加锁过程中可以利用条件阻塞当前线程并临时释放锁,待另外线程获取到锁并在逻辑后通知阻塞线程”激“活.Condition常用在基于异步通信的同步机制实现中,比如达博中的请求和获取应答结果的实现。
条件中主要的方法有2个
-
<李>(1)等待()方法可以阻塞当前线程,并释放锁。李>
<李>(2)在获取锁后可以调用信号()通知被等待()阻塞的线程”激活”。李>
这里的等待(),信号()必须在ReentrantLock #锁()和ReentrantLock #解锁()之间调用。
条件的实现也是利用AbstractQueuedSynchronizer队列来实现,等待()在被调用后先将当前线程加入到等待队列中,然后释放锁,最后阻塞当前线程.signal()在被调用后会先获取等待队列中第一个节点,并将这个节点转化成ReentrantLock中的节点并加入到同步阻塞队列的结尾,这样此节点的上个节点线程释放锁后会激活此节点线程取来获取锁。
等待()源码如下
公众最后空白等待()抛出InterruptedException {//判断是否当前线程是否被中断中断则抛出中断异常 如果(Thread.interrupted ()) 抛出InterruptedException ();//加入等待队列 节点的节点=addConditionWaiter ();//释放当前线程锁 int savedState=fullyRelease(节点); int interruptMode=0;//判断是否在同步阻塞队列,如果不在一直循环到被加入 而(! isOnSyncQueue(节点)){//阻塞当前线程 LockSupport.park(这个);//判断是否被中断 如果((interruptMode=checkInterruptWhileWaiting(节点))!=0) 打破; }//获取锁,如果获取中被中断则设置中断状态 如果(acquireQueued(节点,savedState),,interruptMode !=THROW_IE) interruptMode=重新中断;//清除等待队列中被激“活”的节点 如果节点。nextWaiter !=null)//清理如果取消 unlinkCancelledWaiters ();//如果当前线程被中断,处理中断逻辑 如果(interruptMode !=0) reportInterruptAfterWait (interruptMode); }
主要分以下几步
-
<李>(1)先判断是否当前线程是否被中断中断则抛出中断异常如果未中断调用addConditionWaiter()加入等待队列李>
<李>(2)调用fullyRelease(节点)释放锁使同步阻塞队列的下个节点线程能获取锁。李>
<李>(3)调用isOnSyncQueue(节点)判断是否在同步阻塞队列,这里的加入同步阻塞队列操作是在另一个线程调用信号()后加入,如果不在同步阻塞队列会进行阻塞直到被激活。李>
<李>(4)如果被激活然后调用checkInterruptWhileWaiting(节点)判断是否被中断并获取中断模式。李>
<李>(5)继续调用isOnSyncQueue(节点)判断是否在同步阻塞队列。李>
<李>(6)是则调用acquireQueued(节点,savedState)获取锁,这里如果获取不到也会被阻塞,获取不到原因是在第一次调用isOnSyncQueue(节点)前,可能另一个线程已经调用信号()后加入到同步阻塞队列,然后调用acquireQueued(节点,savedState)获取不到锁并阻塞.acquireQueued(节点,savedState)也会返回当前线程是否被中断,如果被中断设置中断模式。李>
<李>(7)在激活后调用unlinkCancelledWaiters()清理等待队列的已经被激活的节点。李>
<李>(8)最后判断当前线程是否被中断,如果被中断则对中断线程做处理。李>
下面来看下addConditionWaiter()实现
私人节点addConditionWaiter () {//获取等待队列尾部节点 节点t=lastWaiter;//如果尾部状态不为条件,如果已经被激“活”,清理之,然后重新获取尾部节点 如果(t !=零,,t。waitStatus !=Node.CONDITION) { unlinkCancelledWaiters (); t=lastWaiter; }//创建以当前线程为基础的节点,并将节点模式设置成条件 节点的节点=新节点(Thread.currentThread (), Node.CONDITION);//如果尾节点不存在,说明队列为空,将头节点设置成当前节点 如果(t==null) firstWaiter=节点;//如果尾节点存在,将此节点设置成尾节点的下个节点 其他的 t。nextWaiter=节点;//将尾节点设置成当前节点 lastWaiter=节点; 返回节点; }
addConditionWaiter()的逻辑很简单,就是创建以当前线程为基础的节点并把节点加入等待队列的尾部待其他线程处理。
下面来看下fullyRelease(节点节点)实现