条件与等待通知机制

使用Condition接口/实现比传统的等待通知机制有什么优势? 在这里我引用Doug Lea写的评论:

将对象监视器方法(wait,notify和notifyAll)的条件因素排除在不同的对象之外,使每个对象具有多个等待集,并将它们与使用任意Lock实现相结合。 在Lock取代了同步方法和语句的使用的情况下,一个Condition取代了Object监视器方法的使用。

我看到这是一个更加面向对象的实现等待/通知机制的方式。 但是有没有比前者好的优势?

关于条件接口有如上所述的许多优点 ,一些重要的如下:

条件接口带有两个额外的方法

1)boolean awaitUntil(Date截止date)throws InterruptedException:导致当前线程等待,直到它被发送信号或中断,或指定的截止时间过去。

2)awaitUninterruptibly():使当前线程等待,直到它被发信号。

如果当前线程的中断状态在进入该方法时被设置,或者在等待时被中断,它将继续等待直到被发信号。 当它最终从这个方法返回时,它的中断状态仍然会被设置。

上述两种方法都不存在于对象类的默认监视器中,在某些情况下,我们希望设置线程的等待时间,然后我们可以通过Condition接口来实现。

在某些情况下,我们不希望线程被中断,并希望当前线程等待,直到它被发信号,然后我们可以去awaitUninterruptibly方法出现在条件接口。

更多信息条件接口Java文档:

http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/Condition.html#awaitUntil%28java.util.Date%29

最大的问题是wait / notify对于新开发者来说是很容易出错的。 主要的问题是不知道如何正确处理它们会导致晦涩的bug。

  • 如果您在wait()之前调用notify(),则会丢失。
  • 可能有时不清楚notify()和wait()是否在同一个对象上被调用。
  • 没有什么等待/通知需要状态更改,但在大多数情况下这是必需的。
  • wait()可以返回虚假

条件将此function封装到专用组件中,但其行为大致相同。

有一个关于等待/ nofity这个问题之前发布的问题,还有很多, search[java] + wait + notify

当你使用Condition: await()/signal()你可以区分哪个对象或者一组对象/线程得到一个特定的信号。 下面是一个简单的例子,一些线程,生产者,将获得isEmpty信号,而消费者将得到isFull信号:

 private volatile boolean usedData = true;//mutex for data private final Lock lock = new ReentrantLock(); private final Condition isEmpty = lock.newCondition(); private final Condition isFull = lock.newCondition(); public void setData(int data) throws InterruptedException { lock.lock(); try { while(!usedData) {//wait for data to be used isEmpty.await(); } this.data = data; isFull.signal();//broadcast that the data is now full. usedData = false;//tell others I created new data. }finally { lock.unlock();//interrupt or not, release lock } } public void getData() throws InterruptedException{ lock.lock(); try { while(usedData) {//usedData is lingo for empty isFull.await(); } isEmpty.signal();//tell the producers to produce some more. usedData = true;//tell others I have used the data. }finally {//interrupted or not, always release lock lock.unlock(); } } 

@AfterWorkGuinness

信号发送之前不应该设置usedData = true / false

信号码到锁块结束并释放后,顺序无关紧要

具体说明为什么有多个等待组是一个优势:

等待/通知是否有不同的线程正在等待的事情(常见的例子是一个固定大小的阻塞队列,有一些线程把东西放到队列中,当队列满时阻塞,其他线程从队列中取出并阻塞当队列为空时),那么如果使用notify,导致调度程序从等待设置通知中select一个线程,则可能会出现所选线程无法通知特定情况的情况。 例如队列会通知添加一些东西到队列中,但是如果select的线程是一个生产者并且队列已经满了,那么它就不能处理那个通知,你宁可去消费者那里。 内在的locking,你必须使用notifyAll,以确保通知不会丢失。

但是,每次通话都会引起通话stream失,每个线程都会醒来并争夺locking,但是只有一个线程可以取得进展。 其他线程都在争夺locking,直到一次一个,他们可以获得locking,最有可能回到等待。 它产生了很多没有太多好处的争用,最好能够使用通知,并知道只有一个线程被通知,通知与该线程相关。

这是单独条件等待的地方,是一个很大的改进。 队列可以调用一个条件上的信号,并知道它只会唤醒一个线程,这个线程正在等待条件。

条件的API文档有一个代码示例,显示使用多个条件的有界缓冲区,它说:

我们希望保持等待放置线程,并将线程分别放在等待集中,这样我们就可以使用优化,只在缓冲区中的项目或空间变为可用时通知单个线程。