J.U.C — Locks — ReentrantLock(二)

条件变量Condition

Condition实现了synchronized同步器的wait/notify/notifyAll的功能,Condition接口提供的API如下:


Condition需要与Lock绑定,一个Lock可以有多个Condition,获取Condition的方式是lock.newCondition()。Condition的实现类在AQS中的ConditionObject,类部维持了一个等待队列:


  • 获取Condition
lock.newCondition() -->

// ReentrantLock
public Condition newCondition() {
    return sync.newCondition();
}

// ReentrantLock.Sync
final ConditionObject newCondition() {
    return new ConditionObject();
}

                                -->
                                // AQS.ConditionObject
                                public ConditionObject() { }

  •  await()
	public final void await() throws InterruptedException {
                                                                   if (Thread.interrupted())     // 如果当前线程被终端,抛出异常
                                                                       throw new InterruptedException();
                                                                   Node node = addConditionWaiter();     // 1. 将当前线程添加到Condition队列
                                                                   int savedState = fullyRelease(node);     // 2. 释放锁
                                                                   int interruptMode = 0;
                                                                   while (!isOnSyncQueue(node)) {     // 3. 自旋直到被signal或signalAll唤醒
                                                                       LockSupport.park(this);     // 挂起当前线程
                                                                       if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                                                                           break;
                                                                   }
                                                                   if (acquireQueued(node, savedState) && interruptMode != THROW_IE)    // 4. 自旋去获取锁
                                                                       interruptMode = REINTERRUPT;
                                                                   if (node.nextWaiter != null) // clean up if cancelled
                                                                       unlinkCancelledWaiters();
                                                                   if (interruptMode != 0)
                                                                       reportInterruptAfterWait(interruptMode);
                                                               }

                                                               // 1.
                                                               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;
                                                               }

                                                               // 2.
                                                               final int fullyRelease(Node node) {
                                                                   boolean failed = true;
                                                                   try {
                                                                       int savedState = getState();
                                                                       if (release(savedState)) {     // 调用release方法释放锁
                                                                           failed = false;
                                                                           return savedState;
                                                                       } else {
                                                                           throw new IllegalMonitorStateException();
                                                                       }
                                                                   } finally {
                                                                       if (failed)
                                                                           node.waitStatus = Node.CANCELLED;
                                                                   }
                                                               }

                                                               // 3.
                                                               final boolean isOnSyncQueue(Node node) {
                                                                   if (node.waitStatus == Node.CONDITION || node.prev == null)
                                                                       return false;
                                                                   if (node.next != null) // If has successor, it must be on queue
                                                                       return true;

                                                                   return findNodeFromTail(node);
                                                               }
                                                               private boolean findNodeFromTail(Node node) {     // 在sync队列中从尾部到头部查找是不是在sync队列中
                                                                   Node t = tail;
                                                                   for (;;) {
                                                                       if (t == node)
                                                                           return true;
                                                                       if (t == null)
                                                                           return false;
                                                                       t = t.prev;
                                                                   }
                                                               }

  • signal()
				public final void signal() {
                                                                  if (!isHeldExclusively())     // 1. 判断是不是当前线程持有锁,只有持有锁的线程能唤醒其他等待的线程
                                                                      throw new IllegalMonitorStateException();
                                                                  Node first = firstWaiter;
                                                                  if (first != null)
                                                                     doSignal(first);     // 2. 通知Condition队列中的等待最长时间的线程,即firstWaiter
                                                               }

// ReentrantLock.Sync
// 1.
protected final boolean isHeldExclusively() {
    return getExclusiveOwnerThread() == Thread.currentThread();
}
                                                                       // 2.
                                                                       private void doSignal(Node first) {
                                                                           do {
                                                                               if ( (firstWaiter = first.nextWaiter) == null)
                                                                                   lastWaiter = null;
                                                                               first.nextWaiter = null;
                                                                           } while (!transferForSignal(first) &&
                                                                                   (first = firstWaiter) != null);
                                                                       }
                                                                       final boolean transferForSignal(Node node) {
                                                                           if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
                                                                               return false;

                                                                           Node p = enq(node);     // 将节点加入sync队列
                                                                           int ws = p.waitStatus;
                                                                           if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
                                                                               LockSupport.unpark(node.thread);
                                                                           return true;
                                                                       }

事例

假设现在有三个线程陆续调用同一个condition的await
  • 开始状态:thread-1获取锁

    1. thread-1调用await():
                   用thread-1创建节点,并设置waitStatus= -2(Condition),再将thread-1加入Condition队列,队列为空,将firstWaiter和lastWaiter设为thread-1;
                   调用release释放thread-1拥有的锁,并从Sync队列中移除节点;
                   自旋等待唤醒

  • thread-2调用await():

  • thread-3调用await():

  •  当收到signal信号后,会从condition队列中从头开始将节点移到sync队列,并唤醒自旋获取锁
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值