Created
September 11, 2010 18:14
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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