N次重复任务的多线程体系结构

时间:2014-02-10 12:02:43

标签: java multithreading scheduled-tasks threadpool executorservice

我有N个任务,每个任务在其自己的特定延迟间隔(N)之后使用固定的线程池大小重复,通常小于N.

由于线程通常不足,因此应优先执行不同的任务,而不是重复最近完成的任务。

我在考虑使用带有N个嵌套ScheduledThreadPoolExecutors的外部ThreadPoolExecutor。我不确定如何以最佳方式解决这个问题,因为每个类都维护着自己的内部线程池。

2 个答案:

答案 0 :(得分:2)

除了使用由assylias回答的PriorityQueue之外,您还可以通过简单的执行ThreadPoolExecutor和另一个ScheduledExecutorService来解决这个问题,它将在给定的延迟之后插入任务。

因此,每个任务都有执行Runnable和插入Runnable,并且在成功执行后,会告诉ScheduledExecutorService在给定的延迟后运行插入Runnable,然后将任务放回ThreadPoolExecutor。

代码:

// myExecutionTask
void run() {
  doSomeWork();
  scheduledExecutor.schedule(myInsertionRunnable, 1000, TimeUnit.MILLISECONDS);
}

// myInsertionRunnable
void run () {
  threadPoolExecutor.execute(myExecutionTask);
}

实际上,这将自动循环ThreadPoolExecutor中的任务,因为那些已经完成的任务将在队列的末尾。

编辑如评论中所述,在非常繁忙的系统上使用调度程序的fixedRatefixedDelay功能时,稍后添加的任务可能比执行任务更少之前已添加,因为系统似乎更喜欢在决定下一个运行时已经执行的任务。

相比之下,我的解决方案正确地循环了这些任务,尽管在繁忙的系统上无法保证所请求的延迟是准确的。所以它们可能会在以后执行,但至少总是按FIFO顺序执行。

答案 1 :(得分:1)

您可以使用PriorityBlockingQueue并使用时间戳来定义优先级 - 例如:

class Task {
    AtomicLong lastRun;
    Runnable r;

    void run() {
        r.run();
        lastRun.set(System.currentMillis);
    }
}

然后,您的ScheduledExecutorService(一个线程)可以在每个时间间隔(N)将任务N添加到PriorityQueue。

你可以在你的FixedThreadPool中运行一个单独的消费者来自队列(使用反向比较器,以便最近运行的任务的优先级较低)。

这有点粗略,但它应该有用。