Condition 将 Object 监视器方法(wait、notify 和 notifyAll)分解成截然不同的对象,以便通过将这些对象与任意 Lock 实现组合使用,为每个对象提供多个等待池(wait-set)。其中,Lock 替代了 synchronized 方法和语句的使用,Condition 替代了 Object 监视器方法的使用。

条件(也称为条件队列条件变量)为线程提供了一个含义,以便在某个状态条件现在可能为 true 的线程通知它之前,一直挂起该线程(即让其 “等待”)。因为访问此共享状态信息发生在不同的线程中,所以它必须受保护,因此要将某种形式的锁与该条件相关联。等待提供一个条件的主要属性是:以原子方式释放相关的锁,并挂起当前线程,就像 Object.wait 做的那样。

Condition 实例实质上被绑定到一个锁上。要为特定 Lock 实例获得 Condition 实例,请使用其 newCondition() 方法。

作为一个示例,假定有一个绑定的缓冲区,它支持 put 和 take 方法。如果试图在空的缓冲区上执行 take 操作,则在某一个项变得可用之前,线程将一直阻塞;如果试图在满的缓冲区上执行 put 操作,则在有空间变得可用之前,线程将一直阻塞。我们喜欢在单独的等待池中保存 put 线程和 take 线程,这样就可以在缓冲区中的项或空间变得可用时利用最佳规划,一次只通知一个线程。可以使用两个 Condition 实例来做到这一点。

class BoundedBuffer {
final Lock lock = new ReentrantLock();
final Condition notFull = lock.newCondition();
final Condition notEmpty = lock.newCondition(); final Object[] items = new Object[100];
int putptr, takeptr, count; public void put(Object x) throws InterruptedException {
lock.lock();
try {
while (count == items.length)
notFull.await();
items[putptr] = x;
if (++putptr == items.length)
putptr = 0;
++count;
notEmpty.signal();
} finally {
lock.unlock();
}
} public Object take() throws InterruptedException {
lock.lock();
try {
while (count == 0)
notEmpty.await();
Object x = items[takeptr];
if (++takeptr == items.length)
takeptr = 0;
--count;
notFull.signal();
return x;
} finally {
lock.unlock();
}
}
}

Condition 实现可以提供不同于 Object 监视器方法的行为和语义,比如受保证的通知排序,或者在执行通知时不需要保持一个锁。如果某个实现提供了这样特殊的语义,则该实现必须记录这些语义。

注意,Condition 实例只是一些普通的对象,它们自身可以用作 synchronized 语句中的目标,并且可以调用自己的 wait 和 notification 监视器方法。获取 Condition 实例的监视器锁或者使用其监视器方法,与获取和该 Condition 相关的 Lock 或使用其 waiting 和 signalling 方法没有什么特定的关系。为了避免混淆,建议除了在其自身的实现中之外,切勿以这种方式使用 Condition 实例。

Condition 的方法

await()

造成当前线程在接到信号或被中断之前一直处于等待状态。

与此 Condition 相关的锁以原子方式释放,并且出于线程调度的目的,将禁用当前线程,且在发生以下四种情况之一 以前,当前线程将一直处于休眠状态:

  • 其他某个线程调用此 Condition 的 signal() 方法,并且碰巧将当前线程选为被唤醒的线程;或者
  • 其他某个线程调用此 Condition 的 signalAll() 方法;或者
  • 其他某个线程中断当前线程,且支持中断线程的挂起;或者
  • 发生 “虚假唤醒”

在所有情况下,在此方法可以返回当前线程之前,都必须重新获取与此条件有关的锁。在线程返回时,可以保证它保持此锁。

如果当前线程:

  • 在进入此方法时已经设置了该线程的中断状态;或者
  • 在支持等待和中断线程挂起时,线程被中断,

则抛出 InterruptedException,并清除当前线程的中断状态。在第一种情况下,没有指定是否在释放锁之前发生中断测试。

awaitNanos(long nanosTimeout)

造成当前线程在接到信号、被中断或到达指定等待时间之前一直处于等待状态。

与此条件相关的锁以原子方式释放,并且出于线程调度的目的,将禁用当前线程,且在发生以下五种情况之一以前,当前线程将一直处于休眠状态:

  • 其他某个线程调用此 Condition 的 signal() 方法,并且碰巧将当前线程选为被唤醒的线程;或者
  • 其他某个线程调用此 Condition 的 signalAll() 方法;或者
  • 其他某个线程中断当前线程,且支持中断线程的挂起;或者
  • 已超过指定的等待时间;或者
  • 发生 “虚假唤醒”。

在所有情况下,在此方法可以返回当前线程之前,都必须重新获取与此条件有关的锁。在线程返回时,可以保证它保持此锁。

如果当前线程:

  • 在进入此方法时已经设置了该线程的中断状态;或者
  • 在支持等待和中断线程挂起时,线程被中断,

则抛出 InterruptedException,并且清除当前线程的已中断状态。在第一种情况下,没有指定是否在释放锁之前发生中断测试。

在返回时,该方法返回了所剩毫微秒数的一个估计值,以等待所提供的 nanosTimeout 值的时间,如果超时,则返回一个小于等于 0 的值。可以用此值来确定在等待返回但某一等待条件仍不具备的情况下,是否要再次等待,以及再次等待的时间。此方法的典型用法采用以下形式:

synchronized boolean aMethod(long timeout, TimeUnit unit) {
long nanosTimeout = unit.toNanos(timeout);
while (!conditionBeingWaitedFor) {
if (nanosTimeout > 0)
nanosTimeout = theCondition.awaitNanos(nanosTimeout);
else
return false;
}
// ...
}

await(long time, TimeUnit unit)

造成当前线程在接到信号、被中断或到达指定等待时间之前一直处于等待状态。此方法在行为上等效于:

awaitNanos(unit.toNanos(time)) > 0

awaitUntil(Date deadline)

造成当前线程在接到信号、被中断或到达指定最后期限之前一直处于等待状态。

与此条件相关的锁以原子方式释放,并且出于线程调度的目的,将禁用当前线程,且在发生以下五种情况之一以前,当前线程将一直处于休眠状态:

  • 其他某个线程调用此 Condition 的 signal() 方法,并且碰巧将当前线程选为被唤醒的线程;或者
  • 其他某个线程调用此 Condition 的 signalAll() 方法;或者
  • 其他某个线程中断当前线程,且支持中断线程的挂起;或者
  • 指定的最后期限到了;或者
  • 发生 “虚假唤醒”。

在所有情况下,在此方法可以返回当前线程之前,都必须重新获取与此条件有关的锁。在线程返回时,可以保证 它保持此锁。

如果当前线程:

  • 在进入此方法时已经设置了该线程的中断状态;或者
  • 在支持等待和中断线程挂起时,线程被中断,

则抛出 InterruptedException,并且清除当前线程的已中断状态。在第一种情况下,没有指定是否在释放锁之前发生中断测试。

返回值指示是否到达最后期限,使用方式如下:

synchronized boolean aMethod(Date deadline) {
boolean stillWaiting = true;
while (!conditionBeingWaitedFor) {
if (stillWaiting)
stillWaiting = theCondition.awaitUntil(deadline);
else
return false;
}
// ...
}

awaitUninterruptibly()

造成当前线程在接到信号之前一直处于等待状态。

与此条件相关的锁以原子方式释放,并且出于线程调度的目的,将禁用当前线程,且在发生以下三种情况之一以前,当前线程将一直处于休眠状态:

  • 其他某个线程调用此 Condition 的 signal() 方法,并且碰巧将当前线程选为被唤醒的线程;或者
  • 其他某个线程调用此 Condition 的 signalAll() 方法;或者
  • 发生“虚假唤醒”

在所有情况下,在此方法可以返回当前线程之前,都必须重新获取与此条件有关的锁。在线程返回时,可以保证它保持此锁。

如果在进入此方法时设置了当前线程的中断状态,或者在等待时线程被中断,那么在接到信号之前,它将继续等待。当最终从此方法返回时,仍然将设置其中断状态。

signal()

唤醒一个等待线程。

如果所有的线程都在等待此条件,则选择其中的一个唤醒。在从 await 返回之前,该线程必须重新获取锁。

signalAll()

唤醒所有等待线程。

如果所有的线程都在等待此条件,则唤醒所有线程。在从 await 返回之前,每个线程都必须重新获取锁。

Java Concurrency - Condition的更多相关文章

  1. 《Java Concurrency》读书笔记,使用JDK并发包构建程序

    1. java.util.concurrent概述 JDK5.0以后的版本都引入了高级并发特性,大多数的特性在java.util.concurrent包中,是专门用于多线并发编程的,充分利用了现代多处 ...

  2. 深入浅出 Java Concurrency (35): 线程池 part 8 线程池的实现及原理 (3)[转]

    线程池任务执行结果 这一节来探讨下线程池中任务执行的结果以及如何阻塞线程.取消任务等等. 1 package info.imxylz.study.concurrency.future;2 3 publ ...

  3. Java Concurrency in Practice 读书笔记 第十章

    粗略看完<Java Concurrency in Practice>这部书,确实是多线程/并发编程的一本好书.里面对各种并发的技术解释得比较透彻,虽然是面向Java的,但很多概念在其他语言 ...

  4. Java Concurrency - 浅析 CountDownLatch 的用法

    The Java concurrency API provides a class that allows one or more threads to wait until a set of ope ...

  5. Java Concurrency - 浅析 CyclicBarrier 的用法

    The Java concurrency API provides a synchronizing utility that allows the synchronization of two or ...

  6. Java Concurrency - 浅析 Phaser 的用法

    One of the most complex and powerful functionalities offered by the Java concurrency API is the abil ...

  7. Java Concurrency - 线程执行器

    Usually, when you develop a simple, concurrent-programming application in Java, you create some Runn ...

  8. Java Concurrency - Callable & Future

    One of the advantages of the Executor framework is that you can run concurrent tasks that return a r ...

  9. 深入浅出 Java Concurrency (4): 原子操作 part 3 指令重排序与happens-before法则

    转: http://www.blogjava.net/xylz/archive/2010/07/03/325168.html 在这个小结里面重点讨论原子操作的原理和设计思想. 由于在下一个章节中会谈到 ...

随机推荐

  1. window 下cygwin开启了后来又关闭了

    特征: ssh localhost 出现port 27 拒绝访问等 系统日志记录信息: 事件 ID ( 0 )的描述(在资源( sshd )中)无法找到.本地计算机可能没有必要的注册信息或消息 DLL ...

  2. MVC神韵---你想在哪解脱!(十四)

    修正票价字段的精度 前面我们追加数据的时候遗留下来一个问题,就是在追加数据的时候,票价(Price)字段中输入的是9.99元,但是电影清单显示画面中该数据的票价字段显示为10元,这是为什么?这个问题发 ...

  3. OpenNebula config配置详情

    AUTH_MAD=AUTHN=ssh,x509,ldap,server_cipher,server_x509,EXECUTABLE=one_auth_mad DATASTORE_BASE_PATH=/ ...

  4. IIS应用程序池性能分析

    #查看应用程序池和w3wp.exe进程的对应关系iisapp -a C:\windows\system32\inetsrv\appcmd.exe list wp 查看任务管理器: 在性能计数器中找到对 ...

  5. Kerberos和NTLM - SQL Server

    当我们使用Windows Authentication去连接SQL Server的时候,SQL Server可能会使用Kerberos或者是NTLM来进行认证,有时间就会因为认证失败的缘故造成各种登录 ...

  6. java连接数据库的解决方法大全(mysql)

    解决方法一:(最重要的一种方法) 你看下my.ini,有无  [mysql] default-character-set=utf8 [client]  default-character-set=ut ...

  7. HDU 2136 Largest prime factor 參考代码

    #include <iostream> #include <vector> #include <cmath> using namespace std; const ...

  8. Mr.Miss

    umbrella please here my ticket number five sorry sir cloakroom Madam Mr. Mrs Miss lady gentleman mal ...

  9. Codeforces Round #329 (Div. 2) A. 2Char 暴力

    A. 2Char Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/593/problem/A De ...

  10. quartz 2.2.1 jdbc 连接池参数配置

    /** The JDBC database driver. */指定连接驱动 public static final String DB_DRIVER = "driver"; /* ...