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.
The newest version!
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
}