【问题标题】:BlockingQueue does not handle interrupt just before the callBlockingQueue 在调用之前不处理中断
【发布时间】:2014-01-25 20:10:15
【问题描述】:

我正在使用 RabbitMQ,它默认使用 LinkedBlockingQueue 作为消费者。 它有一个阻塞的nextDelivery() 方法,基本上调用队列中的take()

但如果在调用该方法之前被中断,它不会捕获中断。

if (Thread.interrupted()) {
    throw new InterruptedException();
}
// If interrupted here, call below will not throw interrupted exception
rabbit.nextDelivery();

只有在等待时中断命中——这也是 javadoc 中所写的——或者如果先阻塞则命中。

Throws:
    InterruptedException - if interrupted while waiting

我实际上有一个案例,中断恰好在我标记的地方命中。如果我在开始或中间设置睡眠,它会起作用,但假设它总是会起作用仍然是不安全的。

是否有替代 BlockingQueue 实现解决此问题? 我不知道它是否消耗了中断,也许静态方法中存在竞争条件它返回false但以某种方式清除设置值?

编辑:这与Thread.interrupted() 通话或不设置标志无关。如果你注释掉 if block,它又是同样的问题。队列方法一进入就不会抛出InterruptedException,它只是阻塞

【问题讨论】:

  • 如果LinkedBlockingQueue.take() 没有抛出,则Thread 上的中断位未设置。如果有帮助,我会稍微修改一下我的答案。
  • 有没有可能RabbitMQ 使用它自己的LinkedBlockingQueue 而不是java.util.concurrent 中的那个?
  • 我刚刚在rabbit调用之前调用了System.out.println(Thread.currentThread().isInterrupted());,它打印了true(这不是清除位),然后rabbit再次阻塞。所以你是对的,它可能是关于兔子的,我正在调查它
  • 与其试图搞清楚 Rabbit 的 nextDelivery() 调用的内部操作(谁知道或关心它正在使用什么队列植入),您应该告诉我们您正在尝试做什么,您认为您需要能够拦截线程的中断状态。
  • 如果是这种情况,那么rabbit 调用正在清除中断状态之前 调用LinkedBlockingQueue.take()。我在他们的源代码中找不到nextDelivery()rabbit 是什么类型?那不是你的代码?

标签: java concurrency interrupt blockingqueue interrupted-exception


【解决方案1】:

但如果在调用该方法之前被中断,它不会捕获中断。

因此,如果我理解您的问题,那么某些东西正在吞噬InterruptedException 或清除中断标志。以下代码总是为我抛出InterruptedException

Thread.currentThread().interrupt();
new LinkedBlockingQueue<String>().take();

重要的是要意识到当InterruptException被抛出时,中断标志被清除。您应该始终执行以下操作:

try {
    // other methods where this is needed are Object.wait(...), Thread.join(...)
    Thread.sleep(100);
} catch (InterruptedException ie) {
    // re-interrupt the thread
    Thread.currentThread().interrupt();
    // deal with the interrupt by returning or something
    ...
}

见:Why invoke Thread.currentThread.interrupt() when catch any InterruptException?

经常发生的情况是第 3 方代码由于代码错误而无法传播中断状态。那么你通常是 SOL,因为中断会被吞掉,take() 方法不会抛出。

此外,重要的是要意识到Thread.interrupted() 清除中断标志。通常你想使用Thread.currentThread().isInterrupted() 来测试中断标志的状态。

是否有解决此问题的替代 BlockingQueue 实现?

我不确定是否存在问题。

【讨论】:

  • 你确定抓住它会清除标志吗?我原以为它永远不会被设置。如果您从线程的主工作循环返回,也没有太多理由重新中断,这在需要将中断传递给调用者的嵌套方法内部是有意义的。
  • 抓住它会清除标志,是的@millimoose。 stackoverflow.com/questions/4906799/…
  • 我想我的问题是捕获异常的行为是否会清除标志,或者是否在抛出异常时清除标志。然后我现在再次意识到这种区别是相当学术的,因为客户端代码无法观察到差异。
  • 哦,我明白了。是的@millimoose。是当它被抛出时,而不是被抓住。我会改变我的帖子。
  • 它从不执行 catch 块,因为在那之后会发生中断。我的抛出代码也没有执行。所以不再设置标志不是这里的原因
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-25
  • 1970-01-01
  • 1970-01-01
  • 2019-10-28
  • 2014-02-14
  • 2012-03-17
相关资源
最近更新 更多