package io.vivarium.util.concurrency;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
* SimpleFuture provides a simple implementation of the Future interface, adding a put(T value) method and allowing
* threads to wait for the values.
*
* @author juckele
*
* @param <T>
*/
public class SimpleFuture<T> implements Future<T>
{
private volatile T _value;
private volatile boolean _done = false;
private synchronized T getValue()
{
return _value;
}
/**
* GenericFuture objects cannot be cancelled. Calling this method returns false, because the future will not be
* cancelled.
*/
@Override
public boolean cancel(boolean mayInterruptIfRunning)
{
// SimpleFuture does not know how to cancel tasks and always fails to cancel.
return false;
}
/**
* GenericFuture objects cannot be cancelled. Calling this method returns false, because the future is not
* cancelled.
*/
@Override
public boolean isCancelled()
{
// SimpleFuture cannot be cancelled, so is never cancelled.
return false;
}
@Override
public synchronized boolean isDone()
{
return _done;
}
/**
* The SimpleFuture is an externally controlled future. The SimpleFuture is completed by calling put, thus providing
* the value to any other waiting threads.
*
* @param value
* The value to set the future to.
*/
public synchronized void put(T value)
{
_value = value;
_done = true;
}
@Override
public T get() throws InterruptedException, ExecutionException
{
while (!isDone())
{
Thread.sleep(0);
}
return getValue();
}
@Override
public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException
{
long timeoutInMS = unit.toMillis(timeout);
long startWaitTime = System.currentTimeMillis();
while (!isDone() && startWaitTime + timeoutInMS < System.currentTimeMillis())
{
Thread.sleep(0);
}
if (isDone())
{
return getValue();
}
else
{
throw new TimeoutException("Timed out waiting for future. Timeout of " + timeout + " " + unit);
}
}
}