Java中等待条件
我想创建一个线程,当队列变空时将值放入队列中,并在队列不空时等待这一条件。这是我尝试使用的代码,但它打印出
Adding new
Taking Value 1
Taking Value 2
Taking Value 3
Taking Value 4
So it is only work only 一次。问题是什么?
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class SO {
public String test;
public String[] list = new String[] {test};
public static void main(String[] args) {
new SO();
}
public SO() {
go();
}
BlockingQueue<String> qq = new LinkedBlockingQueue<String>();
class Producer implements Runnable {
public void run() {
try {
while (true) {
synchronized (this) {
while (qq.size() > 0)
wait();
System.out.println("Adding new");
qq.put("Value 1");
qq.put("Value 2");
qq.put("Value 3");
qq.put("Value 4");
}
}
} catch (InterruptedException ex) {}
}
}
class Consumer implements Runnable {
public void run() {
try {
while(true) {
System.out.println("Taking " + qq.take()+". "+String.valueOf(qq.size())+" left");
Thread.sleep(1000);
}
} catch (InterruptedException ex) {}
}
}
public void go() {
Producer p = new Producer();
Consumer c = new Consumer();
new Thread(p).start();
new Thread(c).start();
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
wait()
永远不会被通知。wait()
is never notified.wait() 将永远持续下去,因为您从未调用过 notification()。
当您希望唤醒等待线程时,您可以等待队列并调用通知。为此,您可以将 Producer 更改为 read:
并将 Consumer 更改为 read:
正如 Steve 在他的回答中所说,您还可以在消费者线程中使用 wait() ,这样它就可以等待,直到列表中有内容而不是休眠。所以你的代码将变成:
The wait() will continue forever because you never call notify().
You could wait on the queue and call notify on that when you want the waiting thread to wakeup. To do this you would change Producer to read:
And change Consumer to read:
As Steve says in his answer you could also use wait() in the consumer thread so it can wait until there is something in the list rather than sleeping. So your code would become:
既然您使用的是
BlockingQueue
,则不必使用synchronized
,因为BlockingQueue
默认情况下是同步的。如果你想使用同步,那么你应该通过同一个对象进行同步:并且消费者的方法应该包装在
synchronized(theSameObjectInstance)
中以便接收通知,消费者还应该在某个地方“等待”,例如当 qq 时是空的。Sice you are using
BlockingQueue
, you don't have to usesynchronized
, becauseBlockingQueue
is sychronized by default. If you want to use synchronization, than you should synchronize trough the same object:and consumer's method should be wrapped in
synchronized(theSameObjectInstance)
in order to recieve notification, consumer should also "wait" somewhere e.g. when qq is empty.您的要求表明您打算在队列为空时将值放入队列中 - 我认为是多个值,而不仅仅是一个。如果您的需求稍有变化,即您将一个项目放入队列中,并等到它被消耗后再放入另一个项目,那么您就可以使用
java.util.concurrent.Exchanger
。它的行为类似于
BlockingQueue
的深度为一,但它做了更多的事情:它双向传递一个对象,其中每个参与者既是“生产者”又是“消费者”。因此,在“消费者”也准备好返还商品之前,交换者
不会接受“生产者”提供的商品。对于“制作人”来说,这不是“一劳永逸”;而是“一劳永逸”。生产和消费时间是环环相扣的。这可以防止实际的生产者淹没消费者的工作队列——同样,像 BlockingQueue 一样——但它也会阻止生产者直到消费者完成最后一轮工作。在您的情况下,消费者可能没有任何有用的东西可以返回给生产者。无论如何,您可以在参与者之间制定协议。当生产者希望消费者线程关闭时,它可以提供一个空值。一旦消费者接受空值,生产者可能会再进行一轮交换以完成关闭请求并从消费者收集任何最终结果。
Your requirements state that you intend to put values into the queue when it's empty -- several values, I take it, rather than just one. If your requirements change slightly to say that you put one item in the queue and wait until it's consumed before putting another, then you'd be ripe for using
java.util.concurrent.Exchanger
.Its behavior is similar to a
BlockingQueue
of depth one, but it does a little more: It passes an object both ways, where each participant is both a "producer" and a "consumer". Hence, anExchanger
won't accept a "producer"'s offering of an item until the "consumer" is also ready to offer an item back. It's not "fire and forget" for the "producer"; the production and consumption timing is interlocked. This prevents an actual producer from flooding a consumer's work queue -- again, likeBlockingQueue
-- but it also stalls the producer until the consumer has completed the last round of work.In your case, the consumer might not have anything useful to return to the producer. Regardless, you can form a protocol between the participants. When the producer wants the consumer thread to shut down, it can offer a null value. Once the consumer accepts the null value, the producer might do one more round of exchange to finalize the shutdown request and collect any final outcome from the consumer.