我对ScheduledThreadPoolExecutor.scheduleAtFixedRate和可能的并发感到困惑。为什么有线程池?

时间:2016-02-19 05:48:03

标签: java multithreading concurrency

我的混淆始于the api description的方法scheduleAtFixedRate。

  

如果此任务的执行时间超过其周期,那么   后续处决可能会延迟,但不会同时执行   执行。

如果没有并发执行,为什么还有一个线程池?

此外,有没有办法获得并发执行?我希望它们在确切的时间内运行,即使先前的任务还没有完成。我想要并发执行。

2 个答案:

答案 0 :(得分:2)

文档应为:

  

..后续执行[提供的Runnable任务,每次注册] ..将不会同时执行

这并不意味着在所有计划任务中都不会有 no 并发。相反,对于每个任务(通过调用scheduleAtFixedRate创建),Runnable一次只在一个线程上执行 - 如果执行时间超过间隔,则甚至

这是一种明确的设计选择,因为在大多数情况下,任务回调的并发执行是不合需要的,并导致失控的资源螺旋。例如,如果同时执行越来越多的(相同的)Runnables,就会形成“任务炸弹”。

线程池monikor是准确的,因为实现执行它所宣传的操作 - 在任务执行中重用线程。

虽然没有标准的[Thread Pool] Executor具有所请求的行为,但它可以以有限的方式进行模拟。这是因为并发限制是每个已注册的任务(不是每个Runnable),并且可以注册多个“相同”任务:

long targetPeriod = ..;
long n = targetPeriod * 2;
task1 = executor.scheduleAtFixedRate(runnable, 0, n, ..)
task2 = executor.scheduleAtFixedRate(runnable, n/2, n, ..)

实际的执行/计时行为取决于各种其他因素,但是如果它们接管~n / 2(目标期间)以执行,则这两个注册的任务可以同时执行。

答案 1 :(得分:0)

  

有没有办法获得并发执行?我希望它们在确切的时间内运行,即使先前的任务还没有完成。我想要并发执行。

您可以从计划任务中启动(或提交给另一个执行程序)实际任务的另一个线程(假设该速率足够长以启动线程或提交任务)。如果任务持续时间超过您想要的速度,您最终可能会耗尽资源(如另一个答案中所述)。

例如:

ScheduledExecutorService ex = Executors.newScheduledThreadPool(1);
ex.scheduleAtFixedRate(() -> {
        new Thread(() -> {
            //do task
        }).start();
    }, 0, 1, TimeUnit.MINUTES);