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();
    }
}

 优化方案:解决两个问题

  1. 标记BlockingQueue以便它知道它不必等待更多元素
  2. 中间没有中断,只有当队列中的所有项目都被处理并且没有剩余的项目要添加时,处理块才会终止
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();
}

 

posted @ 2022-08-23 11:17  民宿  阅读(737)  评论(0编辑  收藏  举报