生产者消费者请求取消

时间:2011-08-16 17:38:58

标签: java multithreading concurrency producer-consumer executorservice

public class MainClass {

private static final int size = 5;

private ExecutorService prodExec = Executors.newFixedThreadPool(size);
private ExecutorService consExec = Executors.newFixedThreadPool(size);

//main method here

public void start(String[] args) {

    for (int index = 0; index < size; index++) {
        Runnable producer = new Producer(consExec, listOfIds);
        prodExec.execute(producer);
    }

    Runtime.getRuntime().addShutdownHook(new Thread() {
        public void run() {
            prodExec.shutdown();
            try {
                prodExec.awaitTermination(10, TimeUnit.SECONDS);
            } catch (InterruptedException ignore) {
            }

            consExec.shutdown();
            try {
                consExec.awaitTermination(10, TimeUnit.SECONDS);
            } catch (InterruptedException ignore) {
            }
        }
    });
    }
}
public class Producer implements Runnable {

private ExecutorService consExec;
private List<Long> list;

public Producer(ExecutorService exec, List<Long> list) {
    this.consExec = exec;
    this.list = list;
}

public void run() {
    for (Long id: list) {
        data = get data from db for the id
        consExec.execute(new Consumer(data));
    }
}
}
public class Consumer implements Runnable {

public void run() {
    // call web service
}
}

我想处理用户请求关闭的情况可能是按Ctrl + C.我认为这可以在关机钩子中完成。但是,如上面的代码所示,每个Producer获取一个ID列表(250可能是?),即调用db来检索ID的数据并将数据提交给消费者线程,然后消费者线程调用Web服务。

当请求关闭时,如何在每个生产者线程中中断for循环,以便每个线程都不处理尚未处理的ID?我能够让shutDownHook工作,但不确定每个线程如何在run方法中包含逻辑以在关闭请求的情况下退出run()方法。可以通过在外部设置一个布尔变量(AtomicBoolean),每个线程在处理每个id之前检查for循环吗?

据我所知,如果我调用shutdown(),它会执行所有提交的任务然后完成。在这种情况下,由于任务已经在执行程序服务上排队,因此无法停止处理。

如果我调用shutdownNow()而不是shutdown(),它可能会产生意外的结果吗?

2 个答案:

答案 0 :(得分:1)

shutdownNow vs shutdown取决于您是否希望首先完成当前正在运行的任务。

如果你想要他们立即停止你会做两件事。首先调用shutdownNow。第二,在run方法中测试线程的中断状态。

public class Producer implements Runnable {

private ExecutorService consExec;
private List<Long> list;

public Producer(ExecutorService exec, List<Long> list) {
    this.consExec = exec;
    this.list = list;
}

    public void run() {
        for (Long id: list) {
            if(Thread.currentThread().isInterrupted()){
               //the shutdownNow method has been called (or may a future.cancel(true))
            }
            data = get data from db for the id
            consExec.execute(new Consumer(data));
        }
    }
}

你可以在这里看到run方法现在知道当前线程已被中断。然后,该run方法可以清理任何数据并退出

答案 1 :(得分:1)

如果您使用的是Java SE 6+,则可以访问JMX个类。我们发现使用它来“关闭”我们运行的服务很有帮助。

实质上,您将服务注册为JMX服务。并使用驱动程序类将其关闭。

在您的实际服务类中,实现您的逻辑,该逻辑本质上使用无限循环来检查条件是否为真(默认情况下是这样)。

创建另一个连接到JMX服务的驱动程序类,并将循环条件的值修改为false。然后当你达到你的循环条件时,它会(正常地)关闭而不会处理下一组值。