org.jboss.threads.AsyncFutureTask Maven / Gradle / Ivy
Go to download
This artifact provides a single jar that contains all classes required to use remote EJB and JMS, including
all dependencies. It is intended for use by those not using maven, maven users should just import the EJB and
JMS BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up
with different versions on classes on the class path).
The newest version!
/*
* JBoss, Home of Professional Open Source.
* Copyright 2017 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.threads;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.wildfly.common.Assert;
/**
* A base class for implementing asynchronous tasks. This class implements
* {@link java.util.concurrent.Future Future} as well as {@link AsyncFuture}, and
* is approximately equivalent to {@link java.util.concurrent.FutureTask}, however it
* does not implement {@link Runnable} and is somewhat more flexible.
*
* @author David M. Lloyd
*/
public abstract class AsyncFutureTask implements AsyncFuture {
private final Executor executor;
private AsyncFuture.Status status;
private Object result;
private List> listeners;
private final class Reg implements Runnable {
private final AsyncFuture.Listener super T, A> listener;
private final A attachment;
private Reg(final AsyncFuture.Listener super T, A> listener, final A attachment) {
this.listener = listener;
this.attachment = attachment;
}
public void run() {
switch (getStatus()) {
case CANCELLED: listener.handleCancelled(AsyncFutureTask.this, attachment); break;
case COMPLETE: listener.handleComplete(AsyncFutureTask.this, attachment); break;
case FAILED: listener.handleFailed(AsyncFutureTask.this, (Throwable) result, attachment);
}
}
}
/**
* Construct a new instance.
*
* @param executor the executor to use for asynchronous notifications
*/
protected AsyncFutureTask(final Executor executor) {
this.executor = executor;
status = AsyncFuture.Status.WAITING;
}
/**
* Set the successful result of this operation. Once a result is set, calls to this
* or the other {@code set*()} methods are ignored.
*
* @param result the result
* @return {@code true} if the result was successfully set, or {@code false} if a result was already set
*/
protected final boolean setResult(final T result) {
List> list;
synchronized (this) {
if (status == AsyncFuture.Status.WAITING) {
this.result = result;
status = AsyncFuture.Status.COMPLETE;
notifyAll();
list = listeners;
listeners = null;
} else {
return false;
}
}
if (list != null) for (Reg> reg : list) {
safeExecute(reg);
}
return true;
}
/**
* Set the cancelled result of this operation. Once a result is set, calls to this
* or the other {@code set*()} methods are ignored.
*
* @return {@code true} if the result was successfully set, or {@code false} if a result was already set
*/
protected final boolean setCancelled() {
List> list;
synchronized (this) {
if (status == AsyncFuture.Status.WAITING) {
status = AsyncFuture.Status.CANCELLED;
notifyAll();
list = listeners;
listeners = null;
} else {
return false;
}
}
if (list != null) for (Reg> reg : list) {
safeExecute(reg);
}
return true;
}
/**
* Set the failure result of this operation. Once a result is set, calls to this
* or the other {@code set*()} methods are ignored.
*
* @param cause the cause of failure
* @return {@code true} if the result was successfully set, or {@code false} if a result was already set
*/
protected final boolean setFailed(final Throwable cause) {
List> list;
synchronized (this) {
if (status == AsyncFuture.Status.WAITING) {
status = AsyncFuture.Status.FAILED;
result = cause;
notifyAll();
list = listeners;
listeners = null;
} else {
return false;
}
}
if (list != null) for (Reg> reg : list) {
safeExecute(reg);
}
return true;
}
private void safeExecute(final Reg reg) {
try {
executor.execute(reg);
} catch (Throwable t) {
// todo log it
}
}
/**
* Cancel this task. The default implementation of this method does nothing; if the
* task support asynchronous cancel, this method may be overridden to implement it. The
* implementation may choose to support or disregard the {@code interruptionDesired} flag.
* Implementations are allowed to interrupt threads associated with tasks even if the flag is
* {@code false}; likewise, implementations may choose not to interrupt threads even if the
* flag is {@code true}.
*
* @param interruptionDesired {@code true} if interruption of threads is desired
*/
public void asyncCancel(final boolean interruptionDesired) {
}
/** {@inheritDoc} */
public final Status await() throws InterruptedException {
synchronized (this) {
while (status == Status.WAITING) {
wait();
}
return status;
}
}
/** {@inheritDoc} */
public final Status await(final long timeout, final TimeUnit unit) throws InterruptedException {
long remaining = unit.toNanos(timeout);
long now = System.nanoTime();
Status status;
synchronized (this) {
for (;;) {
status = this.status;
if (remaining <= 0L || status != Status.WAITING) {
return status;
}
wait(remaining / 1_000_000L, (int) (remaining % 1_000_000));
remaining -= -now + (now = System.nanoTime());
}
}
}
/** {@inheritDoc} */
public final Status awaitUninterruptibly() {
synchronized (this) {
boolean intr = Thread.interrupted();
try {
while (status == Status.WAITING) try {
wait();
} catch (InterruptedException e) {
intr = true;
}
} finally {
if (intr) {
Thread.currentThread().interrupt();
}
}
return status;
}
}
/** {@inheritDoc} */
public final Status awaitUninterruptibly(final long timeout, final TimeUnit unit) {
long remaining = unit.toNanos(timeout);
long now = System.nanoTime();
Status status;
boolean intr = Thread.interrupted();
try {
synchronized (this) {
for (;;) {
status = this.status;
if (remaining <= 0L || status != Status.WAITING) {
return status;
}
try {
wait(remaining / 1_000_000L, (int) (remaining % 1_000_000));
} catch (InterruptedException e) {
intr = true;
}
remaining -= -now + (now = System.nanoTime());
}
}
} finally {
if (intr) {
Thread.currentThread().interrupt();
}
}
}
/** {@inheritDoc} */
@SuppressWarnings({ "unchecked" })
public final T get() throws InterruptedException, ExecutionException {
synchronized (AsyncFutureTask.this) {
final Status status = await();
switch (status) {
case CANCELLED:
throw Messages.msg.operationCancelled();
case FAILED:
throw Messages.msg.operationFailed((Throwable) result);
case COMPLETE: return (T) result;
default: throw Assert.impossibleSwitchCase(status);
}
}
}
/** {@inheritDoc} */
@SuppressWarnings({ "unchecked" })
public final T get(final long timeout, final TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
synchronized (AsyncFutureTask.this) {
final Status status = await(timeout, unit);
switch (status) {
case CANCELLED:
throw Messages.msg.operationCancelled();
case FAILED:
throw Messages.msg.operationFailed((Throwable) result);
case COMPLETE: return (T) result;
case WAITING:
throw Messages.msg.operationTimedOut();
default: throw Assert.impossibleSwitchCase(status);
}
}
}
/** {@inheritDoc} */
@SuppressWarnings({ "unchecked" })
public final T getUninterruptibly() throws CancellationException, ExecutionException {
synchronized (AsyncFutureTask.this) {
final Status status = awaitUninterruptibly();
switch (status) {
case CANCELLED:
throw Messages.msg.operationCancelled();
case FAILED:
throw Messages.msg.operationFailed((Throwable) result);
case COMPLETE: return (T) result;
default: throw Assert.impossibleSwitchCase(status);
}
}
}
/** {@inheritDoc} */
@SuppressWarnings({ "unchecked" })
public final T getUninterruptibly(final long timeout, final TimeUnit unit) throws CancellationException, ExecutionException, TimeoutException {
synchronized (AsyncFutureTask.this) {
final Status status = awaitUninterruptibly(timeout, unit);
switch (status) {
case CANCELLED:
throw Messages.msg.operationCancelled();
case FAILED:
throw Messages.msg.operationFailed((Throwable) result);
case COMPLETE: return (T) result;
case WAITING:
throw Messages.msg.operationTimedOut();
default: throw Assert.impossibleSwitchCase(status);
}
}
}
/** {@inheritDoc} */
public final Status getStatus() {
synchronized (AsyncFutureTask.this) {
return status;
}
}
/** {@inheritDoc} */
public final void addListener(final Listener super T, A> listener, final A attachment) {
synchronized (AsyncFutureTask.this) {
final Reg reg = new Reg(listener, attachment);
if (status == Status.WAITING) {
if (listeners == null) {
listeners = new ArrayList>();
}
listeners.add(reg);
} else {
safeExecute(reg);
}
}
}
/** {@inheritDoc} */
public final boolean cancel(final boolean interruptionDesired) {
asyncCancel(interruptionDesired);
return awaitUninterruptibly() == Status.CANCELLED;
}
/** {@inheritDoc} */
public final boolean isCancelled() {
return getStatus() == Status.CANCELLED;
}
/** {@inheritDoc} */
public final boolean isDone() {
return getStatus() != Status.WAITING;
}
}