00500005
00500005

Reputation: 4057

Does Java have an indexable multi-queue thread pool?

Is there a Java class such that:

  1. Executable tasks can be added via an id, where all tasks with the same id are guaranteed to never run concurrently
  2. The number of threads can be limited to a fixed amount

A naive solution of a Map would easily solve (1), but it would be difficult to manage (2). Similarly, all thread pooling classes that I know of will pull from a single queue, meaning (1) is not guaranteed.

Solutions involving external libraries are welcome.

Upvotes: 8

Views: 2543

Answers (4)

Estok
Estok

Reputation: 21

Yes, there is such a library now: 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

Upvotes: 1

Alexei Kaigorodov
Alexei Kaigorodov

Reputation: 13535

For each id, you need a SerialExecutor, described in the documentation of java.util.concurrent.Executor. All serial executors delegate work to a ThreadPoolExecutor with given corePoolSize.

Opimized version of SerialExecutor can be found at my code samples.

Upvotes: 4

Stephen C
Stephen C

Reputation: 719239

I think that the simplest solution is to just have a separate queue for each index and a separate executor (with one thread) for each queue.

The only thing you could achieve with a more complex solution would be to use fewer threads, but if the number of indexes is small and bounded that's probably not worth the effort.

Upvotes: 2

yshavit
yshavit

Reputation: 43391

If you don't find something that does this out of the box, it shouldn't be hard to roll your own. One thing you could do is to wrap each task in a simple class that reads on a queue unique per id, e.g.:

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();
    }
}

It should be easy to maintain a map of ids to queues for submitting tasks. That satisfies condition (1), and then you can look for simple solutions to condition (2), such as Executors. newFixedThreadPool

Upvotes: 3

Related Questions