
com.koushikdutta.async.future.SimpleFuture Maven / Gradle / Ivy
package com.koushikdutta.async.future;
import com.koushikdutta.async.AsyncSemaphore;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class SimpleFuture extends SimpleCancellable implements DependentFuture {
AsyncSemaphore waiter;
Exception exception;
T result;
boolean silent;
FutureCallback callback;
public SimpleFuture() {
}
public SimpleFuture(T value) {
setComplete(value);
}
public SimpleFuture(Exception e) {
setComplete(e);
}
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
return cancel();
}
private boolean cancelInternal(boolean silent) {
if (!super.cancel())
return false;
// still need to release any pending waiters
FutureCallback callback;
synchronized (this) {
exception = new CancellationException();
releaseWaiterLocked();
callback = handleCompleteLocked();
this.silent = silent;
}
handleCallbackUnlocked(callback);
return true;
}
public boolean cancelSilently() {
return cancelInternal(true);
}
@Override
public boolean cancel() {
return cancelInternal(silent);
}
@Override
public T get() throws InterruptedException, ExecutionException {
AsyncSemaphore waiter;
synchronized (this) {
if (isCancelled() || isDone())
return getResult();
waiter = ensureWaiterLocked();
}
waiter.acquire();
return getResult();
}
private T getResult() throws ExecutionException {
if (exception != null)
throw new ExecutionException(exception);
return result;
}
@Override
public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
AsyncSemaphore waiter;
synchronized (this) {
if (isCancelled() || isDone())
return getResult();
waiter = ensureWaiterLocked();
}
if (!waiter.tryAcquire(timeout, unit))
throw new TimeoutException();
return getResult();
}
@Override
public boolean setComplete() {
return setComplete((T)null);
}
private FutureCallback handleCompleteLocked() {
// don't execute the callback inside the sync block... possible hangup
// read the callback value, and then call it outside the block.
// can't simply call this.callback.onCompleted directly outside the block,
// because that may result in a race condition where the callback changes once leaving
// the block.
FutureCallback callback = this.callback;
// null out members to allow garbage collection
this.callback = null;
return callback;
}
private void handleCallbackUnlocked(FutureCallback callback) {
if (callback != null && !silent)
callback.onCompleted(exception, result);
}
void releaseWaiterLocked() {
if (waiter != null) {
waiter.release();
waiter = null;
}
}
AsyncSemaphore ensureWaiterLocked() {
if (waiter == null)
waiter = new AsyncSemaphore();
return waiter;
}
public boolean setComplete(Exception e) {
return setComplete(e, null);
}
public boolean setComplete(T value) {
return setComplete(null, value);
}
public boolean setComplete(Exception e, T value) {
FutureCallback callback;
synchronized (this) {
if (!super.setComplete())
return false;
result = value;
exception = e;
releaseWaiterLocked();
callback = handleCompleteLocked();
}
handleCallbackUnlocked(callback);
return true;
}
public FutureCallback getCompletionCallback() {
return new FutureCallback() {
@Override
public void onCompleted(Exception e, T result) {
setComplete(e, result);
}
};
}
public SimpleFuture setComplete(Future future) {
future.setCallback(getCompletionCallback());
setParent(future);
return this;
}
// TEST USE ONLY!
public FutureCallback getCallback() {
return callback;
}
@Override
public SimpleFuture setCallback(FutureCallback callback) {
// callback can only be changed or read/used inside a sync block
synchronized (this) {
this.callback = callback;
if (isDone() || isCancelled())
callback = handleCompleteLocked();
else
callback = null;
}
handleCallbackUnlocked(callback);
return this;
}
@Override
public final > C then(C callback) {
if (callback instanceof DependentCancellable)
((DependentCancellable)callback).setParent(this);
setCallback(callback);
return callback;
}
@Override
public SimpleFuture setParent(Cancellable parent) {
super.setParent(parent);
return this;
}
/**
* Reset the future for reuse.
* @return
*/
public SimpleFuture reset() {
super.reset();
result = null;
exception = null;
waiter = null;
callback = null;
silent = false;
return this;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy