【问题标题】:Does Java have an indexable multi-queue thread pool?Java 是否有可索引的多队列线程池?
【发布时间】:2013-08-01 03:01:56
【问题描述】:

是否有这样的 Java 类:

  1. 可以通过 id 添加可执行任务,保证具有相同 id 的所有任务永远不会同时运行
  2. 可以将线程数限制为固定数量

一个朴素的地图解决方案很容易解决(1),但很难管理(2)。同样,我所知道的所有线程池类都将从单个队列中提取,这意味着 (1) 无法保证。

欢迎涉及外部库的解决方案。

【问题讨论】:

  • @Makky,我一直在专门研究 Spring TaskExecutor
  • @downvoters,为什么这是一个坏问题?这不是一个“请给我代码”的问题,在我看来这将是一个相当常见的多线程用例,并且谷歌搜索不会产生任何明显的结果

标签: java multithreading queue threadpool


【解决方案1】:

是的,现在有这样一个库:https://github.com/jano7/executor

int maxTasks = 10;
ExecutorService underlyingExecutor = Executors.newFixedThreadPool(maxTasks);
KeySequentialBoundedExecutor executor = new KeySequentialBoundedExecutor(maxTasks, underlyingExecutor);

Runnable task = new Runnable() {
    @Override
    public void run() {
        // do something
    }
};

executor.execute(new KeyRunnable<>("ID-1", task)); // execute the task by the underlying executor
executor.execute(new KeyRunnable<>("ID-2", task)); // execution is not blocked by the task for ID-1
executor.execute(new KeyRunnable<>("ID-1", task)); // execution starts when the previous task for ID-1 completes

【讨论】:

    【解决方案2】:

    对于每个 id,您需要一个 SerialExecutor,在 java.util.concurrent.Executor 的文档中进行了描述。所有串行执行器将工作委托给具有给定 corePoolSize 的ThreadPoolExecutor

    SerialExecutor 的优化版本可以在my code samples 找到。

    【讨论】:

    • 这是 Java 文档中隐藏的瑰宝! SerialExecutor 有效地实现了一个多队列线程池,但他们并没有真正明确地做到这一点。
    • @Alexei Kaigorodov,在您重新安排您的 github 存储库后,您的旧答案中的一些链接以 404 结尾 - 自昨天以来,我遇到了 2 个不同的案例。我猜这里提到的是this file,但如果有机会,请尝试修复它们。谢谢!
    【解决方案3】:

    我认为最简单的解决方案是为每个索引设置一个单独的队列,为每个队列设置一个单独的执行器(一个线程)。

    使用更复杂的解决方案唯一可以实现的就是使用更少的线程,但如果索引的数量很小且有界,那么这可能不值得。

    【讨论】:

      【解决方案4】:

      如果您没有找到开箱即用的东西,那么推出自己的产品应该不难。您可以做的一件事是将每个任务包装在一个简单的类中,该类读取每个 id 唯一的队列,例如:

      public static class SerialCaller<T> implements Callable<T> {
          private final BlockingQueue<Caller<T>> delegates;
      
          public SerialCaller(BLockingQueue<Caller<T>> delegates) {
              this.delegates = delegates;
          }
      
          public T call() throws Exception {
              return delegates.take().call();
          }
      }
      

      维护 id 到队列的映射应该很容易,以便提交任务。即满足条件(1),然后可以寻找条件(2)的简单解法,如Executors. newFixedThreadPool

      【讨论】:

      • 您最初的提议似乎更轻松、更易于实施——有什么改变的理由吗?
      • @assylias 我意识到这可能是一个很大的瓶颈。假设您的线程池也仅限于 N 个线程,并且您在 id A 下有 N 个任务,以及在 id B 和 C 下的一些任务。不幸的是,A 的所有任务都被安排了。这意味着 N-1 个线程被阻塞——而不是为 B 或 C 执行任务。
      • 您能否通过添加有关将 id 映射到队列以及提交和轮询任务的源代码来完成此答案?
      猜你喜欢
      • 1970-01-01
      • 2011-02-09
      • 1970-01-01
      • 2015-03-05
      • 2021-05-09
      • 2012-12-06
      • 1970-01-01
      • 2012-03-25
      • 2011-03-25
      相关资源
      最近更新 更多