sirius.kernel.async.Barrier Maven / Gradle / Ivy
/*
* Made with all the love in the world
* by scireum in Remshalden, Germany
*
* Copyright by scireum GmbH
* http://www.scireum.de - [email protected]
*/
package sirius.kernel.async;
import sirius.kernel.health.Exceptions;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Provides a simple barrier to wait for the completion of a set of tasks represented by {@link Barrier}.
*
* A Barrier can be used to block and wait for the completion of a given set of promises. A barrier should
* only be used once and after a call to await, no further promises should be added. Also await
* must only be called once.
*
* The general call pattern looks like that:
*
* {@code
* Barrier b = Barrier.create();
* b.add(somePromise);
* b.add(anotherPromise);
*
* b.await(1, TimeUnit.MINUTE);
* }
*
*
* Always prefer {@link #await(long, java.util.concurrent.TimeUnit)} and specify a sane timeout since something
* might always go wrong and a promise might therefore not complete (in time - or not at all) and your program
* is locked forever.
*
* This barrier can also be used in a non-blocking way, by calling {@link #asFuture()} after the last call to
* {@link #add(Promise)}. If possible, the non-block approach should always be preferred.
*/
@ParametersAreNonnullByDefault
public class Barrier {
private AtomicInteger promisesMade = new AtomicInteger(0);
private AtomicInteger promisesOpen = new AtomicInteger(0);
private Semaphore semaphore = new Semaphore(0);
private Future completionFuture = new Future();
/**
* Creates a new barrier.
*
* @return a new empty barrier.
*/
public static Barrier create() {
return new Barrier();
}
/**
* Adds a promise to the barrier which will be waited for.
*
* Note that one must not call add after calling await.
*
* @param promise the promise to wait for
*/
@SuppressWarnings("unchecked")
public void add(Promise> promise) {
// Reset internal future...
if (completionFuture.isCompleted()) {
completionFuture = new Future();
}
promisesMade.incrementAndGet();
promisesOpen.incrementAndGet();
((Promise