在Java Concurrency In Practice一书(第156页)中,有一条关于毒丸方法的声明:
毒丸仅适用于未绑定的队列。
这是不是意味着使用有界队列我可以得到死锁,或者这是关于一些其他的活跃性问题?它与生产商和客户的数量有关吗?
发布于 2011-12-29 20:29:54
使用有界队列,可以阻止您添加毒丸。
避免此问题的一种方法是在添加毒丸时使有界队列允许更多的毒丸。
发布于 2011-12-31 03:35:38
问题是,在关闭时,队列可能会满。
这取决于队列中的数据在关闭时的价值。你能负担得起把队列中的所有东西都扔掉吗?
当关闭队列的时候,在添加毒丸之前首先排空队列应该是有效的。
void close () throws InterruptedException {
do {
// Empty the queue.
while ( queue.poll(0,TimeUnit.MILLISECONDS) != null ) {
// Throw it away.
}
// Keep draining the queue 'till the pill is swallowed.
} while (!queue.offer(STOP, 0, TimeUnit.MILLISECONDS)) ;
}
当然,如果队列中的项很有价值,您可能希望使用drainto
并保留它们。
还请记住,在毒丸之后,可能会有更多的项目添加到队列中,因为不仅队列可能已满,还可能有线程被阻塞,等待发送到队列中。
发布于 2017-02-25 06:17:07
@gstackoverflow:有界队列的主要问题是它有一个最大容量,所以如果你的有界队列是满的,当你想要添加这个“毒丸”时,你会被阻塞。
请记住,毒丸必须立即放置,不能等到队列有一定的空间,因为此技术用于在发生异常时优雅地关闭消费者(否则会有更好的技术来关闭消费者)。
Java :作为一个例子,我们来看一个简单的例子(这个例子的所有功劳都归功于并发性),它有一个生产者线程和一个消费者线程:
public class CrawlerThread extends Thread { //The Producer Thread
public void run() {
try {
crawl(root);
} catch (InterruptedException e) { /* fall through */ }
finally {
while (true) {
try {
queue.put(POISON);
break;
} catch (InterruptedException e1) { /* retry */ }
}
}
}
private void crawl(File root) throws InterruptedException {
//some code
}
}
public class IndexerThread extends Thread { //The consumer Thread
public void run() {
try {
while (true) {
File file = queue.take();
if (file == POISON)
break;
else
indexFile(file);
}
} catch (InterruptedException consumed) { }
}
}
现在,当您检查生产者线程(CrawlerThread)时,您会看到毒丸要么放在运行的末尾,要么放在一个更可怕的情况下,当出现异常时。
现在假设您想要使用一个有界队列作为生产者和消费者之间的接口,假设队列在时间t已满,并且生产者在时间t发生异常,生产者将不能将毒丸放到队列中,而不是关闭consumer线程,Consumer将仍然等待元素进入队列。因此,如果您使用有界队列,则不推荐使用毒丸方法,因为它可能会导致意外的结果。
https://stackoverflow.com/questions/8667870
复制相似问题