我试图安排一个每秒需要运行约2.25秒的任务。因此我知道3个线程应该足以处理负载。我的代码如下所示:
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(4);
scheduler.scheduleAtFixedRate(new Streamer(), 0, 1000, TimeUnit.MILLISECONDS);
有趣的是,它的行为类似于scheduledAtFixedDelay,延迟为0(线程每2.25秒完成一次)。
我知道,如果一个线程迟到,那scheduleAtFixedRate会迟到。但是不应该给执行者一个更大的线程池来解决这个问题吗?
我可以通过编写3个执行器来每3秒启动一次来轻松解决问题,但这会使管理变得不必要。
这个问题是否有更简单的解决方案?
答案 0 :(得分:3)
您可以使用threadPool和scheduler来实现此效果:
创建一个fixedThreadPool(或其他满足您需求的东西),假设有4个线程 - 线程数应该基于单个任务执行时消耗的时间和任务的调度速率,基本上numberOfThreads = avgExecTimeOfSingleTaks * frequency + someMargin;
然后创建调度程序线程,每秒(或其他所需的时间段)将作业添加到fixedThreadPool队列,然后任务可以重叠。
这种解决问题的方法有额外的冒险:
如果您的任务开始花费超过2.25秒,或者您希望以更高的频率执行它们,那么您所要做的就是向threadPool添加一些线程,而使用另一个答案,您需要重新计算并重新安排一切。因此,这个approch为您提供了更清晰,更易于维护的方法。
答案 1 :(得分:1)
scheduledExecutor会自动阻止任务执行的重叠。因此,您的后续执行将被推迟到上一次执行完毕之后。
Docs:
"如果此任务的执行时间超过其周期,则后续执行可能会延迟,但不会同时执行。"
所以你需要安排 3 任务1)InitDelay 0秒,2)InitDelay 1秒,3)InitDelay 2秒,每个周期为3秒。
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(4);
final Streamer sharedStreamer = new Streamer();
scheduler.scheduleAtFixedRate(sharedStreamer, 0, 3, TimeUnit.SECONDS);
scheduler.scheduleAtFixedRate(sharedStreamer, 1, 3, TimeUnit.SECONDS);
scheduler.scheduleAtFixedRate(sharedStreamer, 2, 3, TimeUnit.SECONDS);
请注意,如果存在大量同步代码,则使用共享资源执行可能会导致执行时间延长。