2009-12-24 438 views
6

让我们假设我有一个消耗另一个线程产生的物品的线程。它的运行方法如下,与INQUEUE是一个BlockingQueue的BlockingQueue.take在什么情况下会抛出异常中断?

boolean shutdown = false; 
while (!shutdown) { 
    try { 
     WorkItem w = inQueue.take(); 
     w.consume(); 
    } catch (InterruptedException e) { 
     shutdown = true; 
    } 
} 

此外,不同的线程将发出信号,有通过中断这个正在运行的线程没有更多的工作项目。如果不需要阻塞以检索下一个工作项,将采取()抛出一个被中断的异常。即如果生产者发出信号表示已完成填充工作队列,是否可能意外地将一些项目留在队列中或错过中断?

+1

你已经差不多了。而不是让* consumer *在中断时将“shutdown”设置为true,而是让* producer *在中断消费者之前将其设置为true。注意这个A)通过避免一个前哨值(“毒丸”)来保持漂亮,B)正确地处理虚假唤醒,C)更通用,因为无论队列是否为空,你都可以故意停止消费者。 – user359996 2012-08-09 20:59:56

回答

4

一个信号终止阻塞队列的好方法是向队列中提交一个'毒'值,指示发生了关闭。这确保了队列的预期行为得到遵守。如果你关心清除队列,调用Thread.interupt()可能不是一个好主意。

提供一些代码:

boolean shutdown = false; 
while (!shutdown) { 
    try { 
     WorkItem w = inQueue.take(); 
     if (w == QUEUE_IS_DEAD) 
      shutdown = true; 
     else 
      w.consume(); 
    } catch (InterruptedException e) { 
     // possibly submit QUEUE_IS_DEAD to the queue 
    } 
} 
+0

这似乎最适用。根据我在罕见情况下可以看到的'完成'中断可以在take()唤醒之前交付,因为更多的东西在队列中。为了防止这种情况发生,我不得不用第二个循环排队。 – Ryan 2009-12-24 20:00:59

3

javadoc,该take()方法将抛出InterruptedException如果等待时中断。

+0

这究竟意味着什么? “”如果在等待时中断“” 编辑:没关系。我从下面的FkYkko的回答中了解到。 – WarLord 2017-11-08 08:45:01

-1

java.concurrency.utils包是由一些最好的并发编程思想设计和实现的。此外,中断线程作为终止它们的手段,明确得到了他们的书“实践中的Java并发”的赞同。因此,如果有任何项目由于中断而留在队列中,我会感到非常惊讶。

+3

在测试中试试它,并且“非常惊讶”;-) – FkYkko 2011-07-08 15:28:00

+0

“聪明的人制作了它”加上“interrupt()中断线程”并不需要“阻塞队列不检查中断状态,直到它们为空”。例如,至少有一个实现(参见http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/concurrent/ArrayBlockingQueue.java#ArrayBlockingQueue。采取)ArrayBlockingQueue调用ReentrantLock.lockInterruptibly(),它会在尝试获取下一个元素之前检查线程的中断状态(如果中断,则抛出InterruptedException)。 – user359996 2012-08-09 20:56:47

2

我想知道同样的事情,并阅读了对于take()的javadoc我相信它只会在获取队列中的所有项目后才会抛出一个中断的异常,因为如果队列中有项目,就不必“等待”。 但我做了一个小测试:

package se.fkykko.slask; 
import java.util.concurrent.ArrayBlockingQueue; 
import java.util.concurrent.BlockingQueue; 
import java.util.concurrent.atomic.AtomicLong; 

public class BlockingQueueTakeTest { 

public static void main(String[] args) throws Exception { 
    Runner t = new Runner(); 
    Thread t1 = new Thread(t); 
    for (int i = 0; i < 50; i++) { 
     t.queue.add(i); 
    } 
    System.out.println(("Number of items in queue: " + t.queue.size())); 
    t1.start(); 
    Thread.sleep(1000); 
    t1.interrupt(); 
    t1.join(); 
    System.out.println(("Number of items in queue: " + t.queue.size())); 
    System.out.println(("Joined t1. Finished")); 

} 

private static final class Runner implements Runnable { 
    BlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(100); 
    AtomicLong m_count = new AtomicLong(0); 

    @Override 
    public void run() { 
     try { 
      while (true) { 
       queue.take(); 
       System.out.println("Took item " + m_count.incrementAndGet()); 
       final long start = System.currentTimeMillis(); 
       while ((System.currentTimeMillis() - start) < 100) { 
        Thread.yield(); //Spin wait 
       } 
      } 
     } 
     catch (InterruptedException ex) { 
      System.out.println("Interrupted. Count: " + m_count.get()); 
     } 
    } 
} 

} 

亚军将采取10-11项,然后完成即采取()将抛出InterruptedException即使仍然在队列中的项目。总结:使用毒丸方法代替,然后你可以完全控制队列中剩下多少。

相关问题