是否存在以下Java类:
地图的天真解决方案很容易解决(1),但管理难度很大(2)。类似地,我所知道的所有线程池类都将从单个队列中提取,这意味着(1)不能得到保证。
欢迎涉及外部图书馆的解决方案。
答案 0 :(得分:4)
对于每个id,您需要一个SerialExecutor,在java.util.concurrent.Executor的文档中描述。所有串行执行程序都将工作委托给具有给定corePoolSize的ThreadPoolExecutor。
可以在my code samples找到最佳版本的SerialExecutor。
答案 1 :(得分: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. newFixedThreadPool
答案 2 :(得分:2)
我认为最简单的解决方案是为每个索引创建一个单独的队列,为每个队列创建一个单独的执行器(带一个线程)。
使用更复杂的解决方案,唯一可以实现的就是使用更少的线程,但如果索引的数量很少且有限,则可能不值得付出努力。
答案 3 :(得分: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