使用Condition接口/实现优于传统的等待通知机制有什么优势?在这里,我引用Doug Lea撰写的评论:
条件将Object监视器方法(wait,notify和notifyAll)分解为不同的对象,通过将它们与使用任意Lock实现相结合,实现每个对象具有多个等待集的效果。如果Lock替换了synchronized方法和语句的使用,则Condition将替换Object监视方法的使用。
我认为这是一种更加面向对象的实现等待/通知机制的方式。但是,前者是否有合理的优势?
答案 0 :(得分:30)
最大的问题是新开发人员的wait / notify容易出错。主要问题是不知道如何正确处理它们可能导致模糊的错误。
Condition将此功能包装到一个专用组件中,但它的行为大致相同。
有一个问题是关于在此之前几分钟发布的等待/ nofity以及许多,更多Search [java]+wait+notify
答案 1 :(得分:29)
使用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();
}
}
答案 2 :(得分:19)
如上所述,条件接口有很多优点,其中一些重要内容如下:
条件界面附带两个额外方法:
1)boolean awaitUntil(Date deadline)抛出InterruptedException: 导致当前线程等待,直到发出信号或中断,或者指定的截止时间结束。
2)awaitUninterruptibly(): 导致当前线程等待直到发出信号。
如果当前线程的中断状态在进入此方法时被设置,或者在等待时被中断,它将继续等待直到发出信号。当它最终从此方法返回时,仍将设置其中断状态。
上述两种方法在对象类的默认监视器中不存在,在某些情况下我们要设置线程等待的截止时间,然后我们可以通过Condition接口来完成。
在某些情况下,我们不希望线程被中断,并且希望当前线程等到它被发出信号,然后我们可以在条件接口中找到awaitUninterruptibly方法。
有关更多信息,请参阅条件接口Java文档:
答案 3 :(得分:1)
@AfterWorkGuinness
在发出信号
之前,您是否应该设置usedData = true / false
信号代码一直到锁定块结束并释放它,所以命令无关紧要
答案 4 :(得分:1)
具体说明为什么拥有多个等待集是一个优势:
使用wait / notify,如果线程正在等待不同的东西(常见的例子是固定大小的阻塞队列,有些线程将事物放入队列并在队列满时阻塞,而其他线程从队列中获取队列为空时队列和阻塞)然后,如果您使用notify,导致调度程序从等待集中选择一个线程进行通知,则可能存在所选线程无法针对特定情况通知的极端情况。例如,队列将通知向队列添加内容,但如果所选线程是生产者并且队列已满,则它无法对该通知执行操作,您宁愿将其发送给使用者。使用内部锁定时,您必须使用notifyAll以确保通知不会丢失。
但是,每次调用时,notifyAll都会产生流失,每个线程都会唤醒并争夺锁定,但只有一个可以取得进展。其他线程都在争夺锁定,直到一次一个,他们可以获得锁定,并且很可能会回到等待状态。它产生了很多争用,没有多少好处,最好是能够使用notify并知道只有一个线程被通知,其中通知与该线程相关。
这就是要等待单独条件的地方是一个很大的改进。队列可以在某个条件下调用信号,并知道它只会唤醒一个线程,该线程专门等待该条件。
API doc for Condition有一个代码示例,显示了对有界缓冲区使用多个条件,它说:
我们希望继续等待put线程并将线程放在单独的等待集中,以便我们可以使用优化,只有当缓冲区中的项或空间可用时才通知单个线程。
答案 5 :(得分:0)
除了其他公认的答案外-由于Condition与Lock对象相关联,因此您可以在类中具有任意的Lock对象集(重写,读取,写入),并具有与之关联的特定条件。然后,您可以使用这些条件集根据实现语义来同步类的不同部分。与等待通知imo相比,这提供了更大的灵活性和明确的行为