检查线程关闭并在关闭后执行任务

时间:2019-05-07 17:13:10

标签: java multithreading

我正在创建具有10个线程的固定大小的线程池,如下所示:

ExecutorService executorService = Executors.newFixedThreadPool(10);

for (int i = 0; i < poolSize; ++i) {
   executorService.execute(factory.get());
}

现在,在生成10个线程之后,它们中的每一个都正在运行一个可运行的线程。这里的runnable由factory.get()提供

现在,我想做一个事情,一旦线程关闭,即它已经完成了一项任务,它将再次选择另一个可运行的对象并开始运行它。因此,基本上检查所有10个线程的状态,如果线程关闭,则再次执行可运行的命令。

我知道我可以做类似的事情,在其中我可以如下调用executorService shutdown()方法:

   while (!executorService.isShutdown()) {
        try {
            executorService.execute(factory.get());
        } catch (RejectedExecutionException e) {
            if (!executorService.isShutdown())
                log.warn("task submission rejected");
        }
    }

但是在这种方法中,问题在于我一直在调用execute函数,这会增加LinkedBlockingQueue并不能达到我的目的。

如果我能以某种方式检查Threads状态,那将是一件好事,因为那样的话,它将避免回头从executor服务中获取更多工作的开销。

请提出如何在代码中做到这一点。

2 个答案:

答案 0 :(得分:1)

您可以使用有界的执行器。以下是code

的Brian Goetz撰写的jcip
/**
 * BoundedExecutor
 * <p/>
 * Using a Semaphore to throttle task submission
 *
 * @author Brian Goetz and Tim Peierls
 */
public class BoundedExecutor {
    private final Executor exec;
    private final Semaphore semaphore;

    public BoundedExecutor(Executor exec, int bound) {
        this.exec = exec;
        this.semaphore = new Semaphore(bound);
    }

    public void submitTask(final Runnable command)
            throws InterruptedException {
        semaphore.acquire();
        try {
            exec.execute(new Runnable() {
                public void run() {
                    try {
                        command.run();
                    } finally {
                        semaphore.release();
                    }
                }
            });
        } catch (RejectedExecutionException e) {
            semaphore.release();
        }
    }
}

然后只需创建并使用它即可:

ExecutorService executorService = Executors.newFixedThreadPool(10);
BoundedExecutor boundedExecutor = new BoundedExecutor(executorService,10);

while (!executorService.isShutdown()) {
    try {
        boundedExecutor.submitTask(factory.get());
    } catch (InterruptedException e) {
    }
}       

这样,您将始终有10个线程在运行,新任务仅在旧任务完成后才提交,并且您可以通过关闭执行程序来停止执行。

答案 1 :(得分:0)

如果要连续运行10个线程,为什么要使用线程池?只需自己启动10个线程即可。

为什么在10个工作线程的顶部有一个“控制器”线程?只需让每个线程要求执行下一个任务即可。

以下内容假设factory.get()是线程安全的。

for (int i = 0; i < 10; i++) {
    new Thread(() -> {
        for (;;) {
            Runnable r = factory.get(); // <-- must be thread-safe
            if (r == null)
                break; // stop thread if no more tasks to execute
            try {
                r.run();
            } catch (Exception e) {
                // log exception here
            }
        }
    }).start();
}

如果需要,将10个线程对象保存在一个数组中。

如果您希望能够在不使factory.get()返回null的情况下关闭线程,请添加一个易失性布尔值,并在循环中进行检查。