io.atlassian.util.concurrent.Executors Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of atlassian-util-concurrent Show documentation
Show all versions of atlassian-util-concurrent Show documentation
This project contains utility classes that are used by
various products and projects inside Atlassian and may have some
utility to the world at large.
package io.atlassian.util.concurrent;
import io.atlassian.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import java.util.function.Supplier;
import javax.annotation.Nonnull;
/**
* Executors utility class.
*/
public final class Executors {
/**
* {@link java.util.concurrent.Executor} that limits the number submitted jobs
* to a fixed upper bound, by blocking the producer thread on submission.
*
* @since 2.6.1
* @see LimitedExecutor for implementation details.
* @param delegate a {@link java.util.concurrent.Executor}.
* @param limit a int.
* @return a {@link java.util.concurrent.Executor}.
*/
public static Executor limited(Executor delegate, int limit) {
return new LimitedExecutor(delegate, limit);
}
/**
* {@link java.util.concurrent.Executor} that limits the number submitted jobs
* to a fixed upper bound, by blocking the producer thread on submission.
*
* @since 2.6.2
* @see LimitedExecutor for implementation details.
* @param delegate a {@link java.util.concurrent.Executor}.
* @return a {@link io.atlassian.util.concurrent.ExecutorSubmitter}.
*/
public static ExecutorSubmitter submitter(Executor delegate) {
return new DefaultSubmitter(delegate);
}
static class DefaultSubmitter implements ExecutorSubmitter {
private final Executor executor;
DefaultSubmitter(final Executor executor) {
this.executor = executor;
}
@Override public void execute(@Nonnull final Runnable command) {
executor.execute(command);
}
@Override public Promise submit(final Callable callable) {
final CallableRunner runner = new CallableRunner(callable);
executor.execute(runner);
return runner.get();
}
@Override public Promise submitSupplier(final Supplier supplier) {
return submit(Suppliers.toCallable(supplier));
}
static class CallableRunner implements Runnable, Supplier> {
enum State {
WAITING, RUNNING, FINISHED
}
final Callable task;
final Promises.SettablePromise promise = Promises.settablePromise();
final AtomicReference state = new AtomicReference<>(State.WAITING);
CallableRunner(Callable taskToRun) {
task = taskToRun;
promise.fail(t -> {
if (promise.isCancelled()) {
state.set(State.FINISHED);
}
});
}
@Override public void run() {
if (state.compareAndSet(State.WAITING, State.RUNNING)) {
try {
final T value = task.call();
if (state.compareAndSet(State.RUNNING, State.FINISHED)) {
promise.set(value);
}
} catch (Exception ex) {
if (state.compareAndSet(State.RUNNING, State.FINISHED)) {
promise.exception(ex);
}
}
}
}
@Override public Promise get() {
return promise;
}
}
}
// /CLOVER:OFF
private Executors() {
throw new AssertionError("cannot instantiate!");
}
// /CLOVER:ON
}