0

我想使用 ThreadPoolExecutor 之类的东西来管理在可用线程上运行的一堆任务。这些任务都是同一类型,但处理不同的帐户。可以定期添加这些帐户的新任务,我希望它检查并且不允许新任务启动,直到同一帐户的旧任务已经完成。最好的方法是什么?

例子

  1. 帐户“234”的任务已启动(通过 ThreadPoolExecutor.execute())

  2. 帐户“238”的任务已启动(通过 ThreadPoolExecutor.execute())

  3. 帐户“234”的新任务已创建但未添加执行,因为第一个“234”任务未完成(最好的检查方法?)

  4. 帐户“238”的任务完成

  5. 帐户“238”的新任务启动(通过 ThreadPoolExecutor.execute()),因为当前没有为该帐户运行

最好的方法是什么?只需让它用 wait/sleep() 检查 Runnable 中的某些检查变量,以完成“234”的第一个任务吗?还是有更好的解决方案?

4

3 回答 3

1

毫无疑问,对这部分 API 有更多经验的人会有更好的主意,但这是我对这个主题的想法......

基本上,我会从“运行”和“等待”队列开始。“运行”队列跟踪当前正在运行的内容,“等待”队列跟踪您阻止的任务。这些队列需要键入某种“组标识符”,以便更容易查找(即Map<String, List<Runnable>),例如,您的帐号

我会考虑覆盖该execute方法。在这里,我会将传入任务与正在运行的队列进行比较,以确定当前是否有任何相关任务正在运行。如果有,我会将新任务放入等待队列。

然后我会覆盖该beforeExecute方法。在这里,我将在“运行”队列中注册任务。

我会覆盖'afterExecute'方法。在这里,我将从“正在运行”队列中删除已完成的任务,查找等待任务的队列(通过已完成任务的组标识符)并通过该execute方法将队列中的第一个任务添加到执行程序中

或者你可以按照路易斯的建议做:P

于 2012-08-17T01:16:53.877 回答
1

一种简单的可能性。也许过于简单。创建 10 个 SingleThreadedExecutor。对于每个任务

  1. 通过使用 accountID mod 10 来“散列”accountID 以找到合适的 SingleThreadedExecutor。(在实践中,accountID 可能不是一个 int,例如,如果它是一个字符串,则它是 hashCode() mod 10)。
  2. 将任务提交给该 SingleThreadedExecutor。

这可能并不理想,因为帐户 238 的处理将被迫等到 358 完成,但至少您确定特定帐户(例如 234)永远不会同时运行。取决于您可以允许多少延迟。显然,您可以使用我描述的执行器的数量和简单的“散列”算法。

于 2012-08-17T02:54:54.237 回答
1

我遇到了同样的问题。我的解决方案是使用 HashSet。

private static HashSet<Integer> runningTasks = new HashSet();

public void run(){
  boolean isAlreadyRunning = false;
  synchronized (runningTasks) {
    if (runningTasks.contains(this.accountId)) {
      isAlreadyRunning = true;
    } else {
      runningTasks.add(this.accountId);
    }
  }
  if(isAlreadyRunning){
    //schedule this task to run later here
    //what I did was to reinsert this task to the task queue 5 seconds later
    return;
  }
  //do your stuffs here

  synchronized (runningTasks) {
    runningTasks.remove(this.accountId);
  }
}
于 2012-08-17T03:32:50.723 回答