如果之前的任务尚未完成,我有兴趣使用ScheduledExecutorService
为任务生成多个线程。例如,我需要每0.5秒处理一个文件。第一个任务开始处理文件,0.5秒后如果第一个线程没有完成第二个线程产生并开始处理第二个文件,依此类推。这可以通过以下方式完成:
ScheduledExecutorService executor = Executors.newScheduledThreadPool(4)
while (!executor.isShutdown()) {
executor.execute(task);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// handle
}
}
现在我的问题:为什么我不能用executor.scheduleAtFixedRate
做到这一点?
我得到的是,如果第一个任务需要更长时间,第二个任务会在第一个任务完成后立即启动,但即使执行程序有线程池,也不会启动新线程。 executor.scheduleWithFixedDelay
很明确 - 它执行任务之间的时间跨度相同,完成任务所需的时间并不重要。所以我可能误解了ScheduledExecutorService
目的。
也许我应该看看另一种执行者?或者只使用我在这里发布的代码?有什么想法吗?
答案 0 :(得分:6)
我通过在每个计划执行中启动嵌套匿名runnable解决了这个问题:
final ScheduledExecutorService service = Executors.newScheduledThreadPool(POOL_SIZE);
final Runnable command = new SlowRunnable();
service.scheduleAtFixedRate(
new Runnable() {
@Override
public void run() {
service.execute(command);
}
}, 0, 1, TimeUnit.SECONDS);
在这个例子中,每个间隔将有一个线程执行一个快速指令,因此当下一个间隔到期时肯定会完成。其余的POOL_SIZE-1线程将并行执行SlowRunnable的run(),这可能需要比单个时间间隔更长的时间。
请注意,虽然我喜欢这个解决方案,因为它最小化代码并重用相同的ScheduledExecutorService,但它必须正确调整大小并且可能无法在每个上下文中使用:如果SlowRunnable太慢以至于POOL_SIZE作业一起执行,没有线程可以及时运行计划任务。
另外,如果你将间隔设置为1 TimeUnit.NANOSECONDS,那么主runnable的执行可能会变得太慢。
答案 1 :(得分:0)
您正在寻找scheduleAtFixedRate方法之一。它以给定的间隔从池中的线程中启动任务,即使先前的任务尚未完成。如果您的线程不足以进行处理,请按照ThreadPoolExecutor docs中的详细说明调整池大小限制。