7

是否有这样的 Java 类:

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

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

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

4

4 回答 4

4

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

SerialExecutor 的优化版本可以在我的代码示例中找到。

于 2013-07-31T16:35:50.703 回答
3

如果你没有找到开箱即用的东西,那么推出自己的产品应该不难。您可以做的一件事是将每个任务包装在一个简单的类中,该类读取每个 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。新的固定线程池

于 2013-07-31T14:31:06.287 回答
2

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

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

于 2013-07-31T14:38:47.927 回答
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
于 2020-05-12T09:24:50.523 回答