Java并发编程之Condition机制
**引言:**Condition存在于Concurrent包中,主要用于替代以前对象Object上的wait()、notify()等方法实现线程间的协作。相比wait()、notify(),Condition根据和Lock的结合,可以实现更复杂和精细的线程协同和等待。从整体上来看Object的wait和notify/notifyAll是与对象监视器配合完成线程间的等待/通知机制,而Condition是与Lock配合完成等待通知机制,前者是java底层级别的,后者是语言级别的,具有更高的可控制性和扩展性。两者除了在使用方式上不同外,在功能特性上还是有很多的不同:
1、Condition能够支持不响应中断,而Object方式不支持。
2、Condition能够支持多个等待队列(new 多个Condition对象),而Object方式只能支持一个。
3、Condition能够支持超时时间的设置,而Object不支持。
**实现原理:**Condition是AQS的内部类。每个Condition对象都包含一个队列(等待队列Condition中拥有首节点firstWaiter和尾节点lastWaiter)。等待队列是一个FIFO的队列,在队列中的每个节点都包含了一个线程引用,该线程就是在Condition对象上等待的线程,如果一个线程调用了Condition.await()方法,那么该线程将会释放锁、构造成节点加入等待队列并进入等待状态。在Object的监视器模型上,一个对象拥有一个同步队列和一个等待队列,而并发包中的Lock拥有一个同步队列和多个等待队列。
Condition的主要方法:
1、await()方法:该方法有两个重载方法,分别是不带参数的await()方法和带超时时间的await()方法,调用该方法的线程是成功获取了锁的线程,也就是同步队列中的首节点,该方法会将当前线程构造节点并加入等待队列中,然后释放同步状态,唤醒同步队列中的后继节点,然后当前线程会进入等待状态。出现以下四种情况前,当前线程将一直处于休眠状态:
(1)、其他某个线程调用此 Condition 的 signal() 方法,并且碰巧将当前线程选为被唤醒的线程。
(2)、其他某个线程调用此 Condition 的 signalAll() 方法。
(3)、其他某个线程中断当前线程,且支持中断线程的挂起。
(4)、发生“虚假唤醒”。
public final void await() throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
ConditionNode node = new ConditionNode();
long savedState = enableWait(node);
LockSupport.setCurrentBlocker(this); // for back-compatibility
boolean interrupted = false, cancelled = false;
while (!canReacquire(node)) {
if (interrupted |= Thread.interrupted()) {
if (cancelled = (node.getAndUnsetStatus(COND) & COND) != 0)
break; // else interrupted after signal
} else if ((node.status & COND) != 0) {
try {
ForkJoinPool.managedBlock(node);
} catch (InterruptedException ie) {
interrupted = true;
}
} else
Thread.onSpinWait(); // awoke while enqueuing
}
LockSupport.setCurrentBlocker(null);
node.clearStatus();
acquire(node, savedState, false, false, false, 0L);
if (interrupted) {
if (cancelled) {
unlinkCancelledWaiters(node);
throw new InterruptedException();
}
Thread.currentThread().interrupt();
}
}
public final boolean await(long time, TimeUnit unit)
throws InterruptedException {
long nanosTimeout = unit.toNanos(time);
if (Thread.interrupted())
throw new InterruptedException();
ConditionNode node = new ConditionNode();
long savedState = enableWait(node);
long nanos = (nanosTimeout < 0L) ? 0L : nanosTimeout;
long deadline = System.nanoTime() + nanos;
boolean cancelled = false, interrupted = false;
while (!canReacquire(node)) {
if ((interrupted |= Thread.interrupted()) ||
(nanos = deadline - System.nanoTime()) <= 0L) {
if (cancelled = (node.getAndUnsetStatus(COND) & COND) != 0)
break;
} else
LockSupport.parkNanos(this, nanos);
}
node.clearStatus();
acquire(node, savedState, false, false, false, 0L);
if (cancelled) {
unlinkCancelledWaiters(node);
if (interrupted)
throw new InterruptedException();
} else if (interrupted)
Thread.currentThread().interrupt();
return !cancelled;
}
2、awaitUninterruptibly()方法:该方法同不带参数的await()作用一样,但是调用该方法的线程不响应中断。出现以下三种情况前,当前线程将一直处于休眠状态:
(1)、其他某个线程调用此 Condition 的 signal() 方法,并且碰巧将当前线程选为被唤醒的线程。
(2)、其他某个线程调用此 Condition 的 signalAll() 方法。
(3)、发生“虚假唤醒”。
public final void awaitUninterruptibly() {
ConditionNode node = new ConditionNode();
long savedState = enableWait(node);
LockSupport.setCurrentBlocker(this); // for back-compatibility
boolean interrupted = false;
while (!canReacquire(node)) {
if (Thread.interrupted())
interrupted = true;
else if ((node.status & COND) != 0) {
try {
ForkJoinPool.managedBlock(node);
} catch (InterruptedException ie) {
interrupted = true;
}
} else
Thread.onSpinWait(); // awoke while enqueuing
}
LockSupport.setCurrentBlocker(null);
node.clearStatus();
acquire(node, savedState, false, false, false, 0L);
if (interrupted)
Thread.currentThread().interrupt();
}
3、awaitNanos()方法:调用该方法的线程进入等待状态直到被通知、中断或者超时,返回值表示剩余超时时间。出现以下五种情况前,当前线程将一直处于休眠状态:
(1)、其他某个线程调用此 Condition 的 signal() 方法,并且碰巧将当前线程选为被唤醒的线程。
(2)、其他某个线程调用此 Condition 的 signalAll() 方法。
(3)、其他某个线程中断当前线程,且支持中断线程的挂起。
(4)、发生“虚假唤醒”。
(5)、已超过指定的等待时间。
public final long awaitNanos(long nanosTimeout)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
ConditionNode node = new ConditionNode();
long savedState = enableWait(node);
long nanos = (nanosTimeout < 0L) ? 0L : nanosTimeout;
long deadline = System.nanoTime() + nanos;
boolean cancelled = false, interrupted = false;
while (!canReacquire(node)) {
if ((interrupted |= Thread.interrupted()) ||
(nanos = deadline - System.nanoTime()) <= 0L) {
if (cancelled = (node.getAndUnsetStatus(COND) & COND) != 0)
break;
} else
LockSupport.parkNanos(this, nanos);
}
node.clearStatus();
acquire(node, savedState, false, false, false, 0L);
if (cancelled) {
unlinkCancelledWaiters(node);
if (interrupted)
throw new InterruptedException();
} else if (interrupted)
Thread.currentThread().interrupt();
long remaining = deadline - System.nanoTime(); // avoid overflow
return (remaining <= nanosTimeout) ? remaining : Long.MIN_VALUE;
}
4、awaitUntil()方法:调用该方法的线程进入等待状态直到被通知、中断或者到某个时间。如果没有到指定时间就被通知,方法返回true,否则,表示到了指定时间,返回false。出现以下五种情况前,当前线程将一直处于休眠状态:
(1)、其他某个线程调用此 Condition 的 signal() 方法,并且碰巧将当前线程选为被唤醒的线程。
(2)、其他某个线程调用此 Condition 的 signalAll() 方法。
(3)、其他某个线程中断当前线程,且支持中断线程的挂起。
(4)、发生“虚假唤醒”。
(5)、指定的最后期限到了。
public final boolean awaitUntil(Date deadline)
throws InterruptedException {
long abstime = deadline.getTime();
if (Thread.interrupted())
throw new InterruptedException();
ConditionNode node = new ConditionNode();
long savedState = enableWait(node);
boolean cancelled = false, interrupted = false;
while (!canReacquire(node)) {
if ((interrupted |= Thread.interrupted()) ||
System.currentTimeMillis() >= abstime) {
if (cancelled = (node.getAndUnsetStatus(COND) & COND) != 0)
break;
} else
LockSupport.parkUntil(this, abstime);
}
node.clearStatus();
acquire(node, savedState, false, false, false, 0L);
if (cancelled) {
unlinkCancelledWaiters(node);
if (interrupted)
throw new InterruptedException();
} else if (interrupted)
Thread.currentThread().interrupt();
return !cancelled;
}
5、signal()方法:唤醒一个等待在Condition上的线程,该线程从等待方法返回前必须获得与Condition相关联的锁。
public final void signal() {
ConditionNode first = firstWaiter;
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
if (first != null)
doSignal(first, false);
}
6、signalAll()方法:唤醒所有等待在Condition上的线程,能够从等待方法返回的线程必须获得与Condition相关联的锁。
public final void signalAll() {
ConditionNode first = firstWaiter;
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
if (first != null)
doSignal(first, true);
}
本文参考
本文主要参考以下文章,谨以技术分享为目的,将此文搬到CSDN上,如有侵权问题请联系本人,乐于分享提高。
作者: DivineH
链接:https://blog.csdn.net/qq_38293564/article/details/80554516