并发问题 - 阻止队列

时间:2013-10-11 14:14:21

标签: java concurrency

我对并发感到困惑 - 我试图阻止消费者线程运行,如果生产者关闭但是如果消费者在take()上被阻止则会出现问题。我尝试添加一个posion药丸,使用布尔标志中断当前线程,但仍无济于事。

请有人帮忙告诉我哪里出错了。感谢。

public class TestPoisonPill implements Runnable {
    private BlockingQueue<String> queue = new ArrayBlockingQueue<String>(1);
    private volatile boolean stopped = false;

    public void addToQueue(String event) throws InterruptedException{
        System.out.println("in add to queue");
        if(event != null){
            try {
                queue.put(event);
            } catch (InterruptedException e) {
                stopped = true;
                queue.put("Poison");
                System.out.println("Unable to add the event to the queue, order routing processing is stopped");
                throw e;
            }
        }
    }

    @Override
    public void run() {
        while(!stopped){
            try {
                if(queue.size() > 0){
                    String string = queue.take();
                    System.out.println("taken " + string + "from the queue");
                }else{
                    continue;
                }
            }
            catch (InterruptedException e) {
                stopped = true;
            }
        }
    }

    public boolean isStopped(){
        return stopped;
    }

    protected BlockingQueue<String> getQueue() {
        return queue;
    }

    protected void setBoolean(boolean b){
        this.stopped = b;
    }

    public static void main(String[] args) throws InterruptedException{
        ExecutorService exec = Executors.newSingleThreadExecutor();
        final TestPoisonPill t = new TestPoisonPill();
        exec.execute(t);
        ExecutorService exec2 = Executors.newSingleThreadExecutor();
        Runnable addTask = new Runnable() {
            public void run() {
                while (true) {
                    try {
                        t.addToQueue("hi");
                        Thread.sleep(100);
                    } catch (InterruptedException ex) {
                        System.out.println("add task interrupted ");
                        t.setBoolean(true);
                        break;
                    }
                }
            }
        };
        exec2.execute(addTask);
        Thread.sleep(1000);
        exec2.shutdownNow();
    }
}

2 个答案:

答案 0 :(得分:3)

  

与并发混淆 - 我试图阻止消费者线程运行如果生产者关闭但是如果消费者在take()上被阻止则会出现问题

如果您的问题是您的计划没有停止,我认为您错过了exec.shutdownNow()的{​​{1}}。这将中断你的第一个线程,如果你将你的循环更改为:

ExecutorService

如果没有中断标志检查,线程将看不到任何中断。中断只是在线程上设置的标志。某些方法(如while (!stopped && !Thread.currentThread().isInterrupted()) { Thread.sleep(...))抛出BlockingQueue.take()当线程被中断但您的消费者正在旋转并且从不调用InterruptedException

真的,消费者中的旋转循环是一个非常糟糕的模式。它应该只调用take()然后使用中断让你的生产者实际提交一个中毒的药丸。类似的东西:

queue.take()

如果你正确使用中断,你真的不需要while (!Thread.currentThread().isInterrupted()) { String string; try { string = queue.take(); } catch (InterruptedException e) { break; } // here is where you could check for a poison pill // something like: if (string == STOP_PILL) break; System.out.println("taken " + string + "from the queue"); } 标志。

你提到尝试了“中毒丸”。对于其他人来说,当你在队列中放置一个特定的“特殊”对象时,一个有毒的药丸是消费者用来知道何时关闭的。以下内容应该有效:

stopped

最后,当您可以轻松使用时,您正在使用2个private static final String STOP_PILL = "__STOP_PLEASE!!__"; ... // the consumer removes from the queue String string = queue.take(); // it tests to see if it a pill, == is better than .equals here if (string == STOP_PILL) { // the consumer should stop break; } ... // to stop the consumer, the producer puts the pill into the queue queue.put(STOP_PILL); 个实例。我想这里的重点是只打断其中一个而不是FYI。您可以使用单个ExecutorService来创建所需的线程数。

答案 1 :(得分:0)

您永远不会关闭exec执行者,只关注exec2,因此运行TestPoisonPill的主题永远不会中断。