package org.zstack.core.thread;
import org.zstack.utils.Utils;
import org.zstack.utils.logging.CLogger;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
public abstract class AbstractFuture<T> implements Future<T> {
private static CLogger logger = Utils.getLogger(AbstractFuture.class);
protected volatile Throwable exception;
protected AtomicBoolean done = new AtomicBoolean(false);
protected AtomicBoolean canceled = new AtomicBoolean(false);
protected volatile T ret;
protected final Object task;
public AbstractFuture(Object task) {
this.task = task;
this.exception = null;
this.ret = null;
}
private void doWait(long timeout) throws InterruptedException, TimeoutException {
synchronized (this) {
while (!isDone() && !isCancelled()) {
this.wait(timeout);
if (isCancelled()) {
throw new CancellationException(task.getClass().getCanonicalName() + " has been cancelled");
}
if (!isDone()) {
throw new TimeoutException("Timeout after " + timeout + " milliseconds");
}
}
}
}
@Override
public T get() throws InterruptedException, ExecutionException {
if (isCancelled()) {
throw new CancellationException(task.getClass().getCanonicalName() + " has been cancelled");
}
try {
doWait(0);
} catch (TimeoutException e) {
// pass on purpose
}
if (exception != null) {
throw new ExecutionException(exception);
}
return ret;
}
@Override
public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
if (isCancelled()) {
throw new CancellationException(task.getClass().getCanonicalName() + " has been cancelled");
}
doWait(unit.toMillis(timeout));
if (exception != null) {
throw new ExecutionException(exception);
}
return ret;
}
@Override
public boolean isCancelled() {
return canceled.get();
}
@Override
public boolean isDone() {
return done.get();
}
protected void done() {
synchronized (this) {
if (!done.compareAndSet(false, true)) {
return;
}
this.notifyAll();
}
}
protected void cancel() {
synchronized (this) {
if (!canceled.compareAndSet(false, true)) {
return;
}
this.notifyAll();
}
}
public void finish(T result) {
ret = result;
done();
}
}