Skip to content

Instantly share code, notes, and snippets.

@abhin4v
Created September 11, 2010 18:14
Show Gist options
  • Save abhin4v/575412 to your computer and use it in GitHub Desktop.
Save abhin4v/575412 to your computer and use it in GitHub Desktop.
A promise is a Future which will be fulfilled later by the promise maker
package net.abhinavsarkar.util;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
/**
* A promise is a {@link Future} which will be fulfilled later by the promise
* maker. Getting the value from the promise blocks until the promise maker
* fulfills the promise.
*
* <p>A promise cannot be canceled.</p>
*
* @author Abhinav Sarkar
*
* @param <T> The type of the value promised.
*/
public class Promise<T> implements Future<T>, Comparable<Promise<T>> {
private final CountDownLatch latch = new CountDownLatch(1);
private final AtomicReference<T> valueRef = new AtomicReference<T>();
private final AtomicBoolean cancelled = new AtomicBoolean(false);
/**
* Cancelling a promise means breaking the promise. After a promise has
* been cancelled, calling {@link #get()} will throw {@link CancellationException}.
*/
public boolean cancel(final boolean mayInterruptIfRunning) {
if (!isDone()) {
if (cancelled.compareAndSet(false, true)) {
latch.countDown();
return true;
} else {
return false;
}
} else {
return false;
}
}
/**
* Fulfills a promise with the provided value. All the calls to
* {@link #get()} will block before the promise maker calls this method.
* After the call to this method, all calls to {@link #get()} will return
* the value that was provided by the promise fulfiller.
*
* @param value The value to fulfill the promise with.
* @return Whether the promise was fulfilled or not. If the promise has
* already been fulfilled, returns false else true.
*/
public boolean fulfill(final T value) {
if (value == null) {
throw new IllegalArgumentException("promise value can't be null");
}
if (!isDone()) {
if (valueRef.compareAndSet(null, value)) {
latch.countDown();
return true;
} else {
return false;
}
} else {
return false;
}
}
/**
* Gets the value of this promise if it has been fulfilled, else blocks
* until it is fulfilled. If the promise has been cancelled, throws
* {@link CancellationException}.
*/
public T get() throws InterruptedException {
if (cancelled.get()) {
throw new CancellationException();
}
latch.await();
return valueRef.get();
}
public T get(final long timeout, final TimeUnit unit)
throws InterruptedException, TimeoutException {
if (cancelled.get()) {
throw new CancellationException();
}
if (latch.await(timeout, unit)) {
return valueRef.get();
} else {
throw new TimeoutException();
}
}
public boolean isCancelled() {
return cancelled.get();
}
public boolean isDone() {
return latch.getCount() == 0;
}
public int compareTo(final Promise<T> o) {
return Float.valueOf(Math.signum(this.hashCode() - o.hashCode())).intValue();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment