Java 如何中断在 take() 上阻塞的 BlockingQueue?
如下阻塞队列+线程的代码,很常见,当服务停止时,如何停止被BlockingQueue阻塞的线程?
public class BlackingQueueTest { public static void main(String[] args) { BlockingQueue<Integer> blockingQueue = new ArrayBlockingQueue(10); blockingQueue.add(5); blockingQueue.add(-1); final Thread thread = new Thread(new Runnable() { @Override public void run() { while (true) { try { Integer el = blockingQueue.take(); System.out.println(el); } catch (InterruptedException e) { } } } }); thread.start(); } }
两种解决方案
方案一:使用poll
代替take
,这将允许处理线程在等待一段时间而没有新输入时超时并终止。
public class BlackingQueueTest { public static void main(String[] args) { BlockingQueue<Integer> blockingQueue = new ArrayBlockingQueue(10); blockingQueue.add(5); blockingQueue.add(-1); final Thread thread = new Thread(new Runnable() { @Override public void run() { while (true) { try { Integer el = blockingQueue.poll(5, TimeUnit.SECONDS); System.out.println(el); if (el == null) { break; } } catch (InterruptedException e) { } } } }); thread.start(); } }
方案二:判断BlockingQueue是否未空,中断处理
public class BlackingQueueTest { public static void main(String[] args) { BlockingQueue<Integer> blockingQueue = new ArrayBlockingQueue(10); blockingQueue.add(5); blockingQueue.add(-1); final Thread thread = new Thread(new Runnable() { @Override public void run() { while (true) { try { Integer el = blockingQueue.take(); System.out.println(el); if (el == null) { break; } } catch (InterruptedException e) { } } } }); thread.start(); } }
优化方案:解决两个问题
- 标记
BlockingQueue
以便它知道它不必等待更多元素 - 中间没有中断,只有当队列中的所有项目都被处理并且没有剩余的项目要添加时,处理块才会终止
class MyObjHandler implements Runnable { private final BlockingQueue<MyObj> queue; public volatile boolean Finished; //VOLATILE GUARANTEES UPDATED VALUE VISIBLE TO ALL public MyObjHandler(BlockingQueue queue) { this.queue = queue; Finished = false; } @Override public void run() { while (true) { try { MyObj obj = queue.poll(100, TimeUnit.MILLISECONDS); if(obj!= null)//Checking if job is to be processed then processing it first and then checking for return { // process obj here // ... } if(Finished && queue.isEmpty()) return; } catch (InterruptedException e) { return; } } } } public void testHandler() { BlockingQueue<MyObj> queue = new ArrayBlockingQueue<MyObj>(100); MyObjHandler handler = new MyObjHandler(queue); new Thread(handler).start(); // get objects for handler to process for (Iterator<MyObj> i = getMyObjIterator(); i.hasNext(); ) { queue.put(i.next()); } // what code should go here to tell the handler to stop waiting for more objects? handler.Finished = true; //THIS TELLS HIM //If you need you can wait for the termination otherwise remove join myThread.join(); }