int capacity = ...
BlockingQueue q = new LinkedBlockingQueue<Element>(capacity);
现在,我确实感到有点荒谬的问这个,但是当谈到java并发时我并不是特别精明,所以我会很感激选择正确排队方式的一些帮助(并且实际上会出列,但我希望我们清理了一个,另一个将自行落实到位。)
当然有
while(!q.offer(e));
但我对在多线程环境中旋转实现有点警惕。
我做不到
synchronized(q){
while(!q.offer(e))q.wait();
}
或者是因为唤醒调用会转到Condition
的内部(私有)实例,这意味着这将是一个自杀式的避孕药实现。
但是,我也不是特别喜欢
try{
q.put(e);
}catch(InterruptedException ex){}
(即使它确实似乎是在线示例中的热门选择)因为虽然这会等待我,但我知道没有可靠的方法来检测异常何时会迫使我再试一次。 我可以做类似
的事情boolean success = false;
do{
try{
q.put(e);
success = true;
}catch(InterruptedException ex){}
}while(!success)
但是如果异常发生在put
和success
的分配之间,那么我最终会多次将相同的元素排入队列。
我能做到
boolean success = true;
do{
try{
q.put(e);
}catch(InterruptedException ex){
success = false;
}
}while(!success)
但是我记得曾经读过(回头)你不应该依赖条件的异常处理(尽管我似乎不记得为什么不鼓励这样做。)
那么......我有什么选择?我需要旋转还是有更聪明的东西?
答案 0 :(得分:1)
put()
实施将是正确的,阻止直到中断或成功。 offer()
是一个坏主意,如果您正在做的就是旋转(请参阅免责声明的第一条评论)。
正如尼古拉斯解释的那样,对InterruptedException
的处理并不简单,并且很大程度上取决于你的其他代码在做什么,而是你对&#34;如果异常发生在put和成功的分配&#34;,永远不会发生:阻塞调用(如put()
)可以抛出该异常,但不能在put()
与赋值之间或在赋值时发生。
最后,没有必要同步任何事情。许多java.util.concurrent
类的主要思想是避免或抽象出显式同步。
答案 1 :(得分:1)
抓住InterruptedException
并不是一个好习惯,因为您的代码将不再响应中断。 InterruptedException
通常由响应中断(当前Thread
被中断)的方法引发,例如await
,wait
,join
类型的方法, sleep
和其他许多人一样,这不应该被视为失败,而是实际上,Thread
的状态变化需要加以考虑。
正如 Brian Goetz 在Java Concurrency in Practice
中解释的那样,我引用:
当您的代码调用抛出
InterruptedException
的方法时,那么 你的方法也是一种阻止方法,并且必须有一个计划 应对中断。对于库代码,基本上有两个 选择:传播InterruptedException。这通常是最明智的策略,如果你可以逃脱它只是传播
InterruptedException
给你的来电者。这可能涉及不捕捉InterruptedException
,或者抓住它并在之后重新扔掉它 执行一些简短的活动清理。恢复中断。有时您无法抛出
InterruptedException
,例如当您的代码属于某个代码时Runnable
。在这些情况下,您必须抓住InterruptedException
并通过调用interrupt
来恢复中断状态 当前线程,以便调用堆栈上方的代码可以看到一个 发出了中断。
因此,在您的情况下,您应该只使用put(E)
,因为它会使调用线程在需要时等待空间可用,传播InterruptedException
以便继续对中断做出反应。
但是如果是的话,我最终会多次将相同的元素排入队列 异常发生在
put
和赋值之间success
。
这可以简单地从不发生,因为boolean
的赋值将从不抛出任何异常(在解除封锁的情况下除了NPE)。并且只有响应中断的方法才会抛出如上所述的这种异常,这显然不是指派的情况。
答案 2 :(得分:0)
来自LinkedBlockingQueue Javadoc的几点:
put
方法只会在两种情况下抛出异常:
InterruptedException
s。null
,这完全是另一个错误。总的来说,您可以使用put
等待空间可用。如果抛出这些特殊异常中的任何一个,那么你无论如何都不应该重试。