use*_*erx 65 java concurrency multithreading
与传统的等待通知机制相比,使用Condition接口/实现的优势是什么?在这里,我引用Doug Lea撰写的评论:
条件因素将Object监视器方法(wait,notify和notifyAll)分解为不同的对象,以通过将它们与使用任意Lock实现相结合来实现每个对象具有多个等待集的效果.如果Lock替换了synchronized方法和语句的使用,则Condition将替换Object监视方法的使用.
我认为这是一种更加面向对象的实现等待/通知机制的方式.但是,前者是否有合理的优势?
Pet*_*rey 31
最大的问题是新开发人员容易出错等待/通知.主要问题是不知道如何正确处理它们可能导致模糊的bug.
Condition将此功能包装到专用组件中,但它的行为大致相同.
有一个关于wait/nofity在此之前发布的几分钟的问题以及许多,更多的Search [java] + wait + notify
kas*_*ere 30
使用时,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();
}
}
Run Code Online (Sandbox Code Playgroud)
小智 21
如上所述有关条件接口的许多优点,一些重要的如下:
条件接口附带两个额外的方法:
1)boolean awaitUntil(Date deadline)throws InterruptedException: 使当前线程等到信号通知或中断,或指定的截止时间过去.
2)awaitUninterruptibly(): 使当前线程等待直到发出信号.
如果在进入此方法时设置了当前线程的中断状态,或者在等待时它被中断,它将继续等待直到发出信号.当它最终从此方法返回时,仍将设置其中断状态.
上面两个方法在对象类中的默认监视器中不存在,在某些情况下我们要设置线程等待的截止时间,然后我们可以通过Condition接口来完成.
在某些情况下,我们不希望线程被中断,并且希望当前线程等到它被发出信号,然后我们可以在条件接口中找到awaitUninterruptibly方法.
有关更多信息条件接口Java文档:
具体来说为什么拥有多个等待集是一个优势:
如果线程正在等待不同的事物,则使用 wait/notify(常见的例子是固定大小的阻塞队列,一些线程将事物放入队列并在队列满时阻塞,而其他线程从队列中取出并阻塞)当队列为空时)然后如果您使用通知,导致调度程序从等待集中选择一个线程进行通知,您可能会遇到一些极端情况,即所选线程对特定情况的通知不感兴趣。例如,队列将通知向队列中添加某些内容,但如果所选线程是生产者并且队列已满,则它无法对该通知采取行动,您宁愿将其发送给消费者。使用内在锁定,您必须使用notifyAll以确保通知不会丢失。
但是notifyAll每次调用都会引起混乱,每个线程都会醒来并争夺锁,但只有一个线程可以取得进展。其他线程都在争夺锁,直到它们一次一个地获得锁并且很可能返回等待状态。它会产生大量争用,但没有多大好处,最好能够使用通知并知道仅通知一个线程,其中通知与该线程相关。
这就是拥有单独的条件来等待是一个很大的改进。队列可以在某个条件上调用信号,并知道它将仅唤醒一个线程,该线程专门等待该条件。
Condition 的 API 文档有一个代码示例,显示了对有界缓冲区使用多个条件,它说:
我们希望继续等待放置线程并将线程放入单独的等待集中,以便我们可以使用优化,即当缓冲区中的项目或空间可用时,一次仅通知单个线程。