remove Windows support, revert new guava to small version

This commit is contained in:
Sen 2025-03-25 11:31:48 +01:00
parent fd84384f10
commit 920405d8c5
264 changed files with 22715 additions and 377 deletions

View file

@ -0,0 +1,392 @@
/*
* Copyright (C) 2007 The Guava Authors
*
* 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 game.future;
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 java.util.concurrent.locks.AbstractQueuedSynchronizer;
/**
* An abstract implementation of the {@link ListenableFuture} interface. This
* class is preferable to {@link java.util.concurrent.FutureTask} for two
* reasons: It implements {@code ListenableFuture}, and it does not implement
* {@code Runnable}. (If you want a {@code Runnable} implementation of {@code
* ListenableFuture}, create a {@link ListenableFutureTask}, or submit your
* tasks to a {@link ListeningExecutorService}.)
*
* <p>This class implements all methods in {@code ListenableFuture}.
* Subclasses should provide a way to set the result of the computation through
* the protected methods {@link #set(Object)} and
* {@link #setException(Throwable)}. Subclasses may also override {@link
* #interruptTask()}, which will be invoked automatically if a call to {@link
* #cancel(boolean) cancel(true)} succeeds in canceling the future.
*
* <p>{@code AbstractFuture} uses an {@link AbstractQueuedSynchronizer} to deal
* with concurrency issues and guarantee thread safety.
*
* <p>The state changing methods all return a boolean indicating success or
* failure in changing the future's state. Valid states are running,
* completed, failed, or cancelled.
*
* <p>This class uses an {@link ExecutionList} to guarantee that all registered
* listeners will be executed, either when the future finishes or, for listeners
* that are added after the future completes, immediately.
* {@code Runnable}-{@code Executor} pairs are stored in the execution list but
* are not necessarily executed in the order in which they were added. (If a
* listener is added after the Future is complete, it will be executed
* immediately, even if earlier listeners have not been executed. Additionally,
* executors need not guarantee FIFO execution, or different listeners may run
* in different executors.)
*
* @author Sven Mawson
* @since 1.0
*/
abstract class AbstractFuture<V> implements ListenableFuture<V> {
/** Synchronization control for AbstractFutures. */
private final Sync<V> sync = new Sync<V>();
// The execution list to hold our executors.
private final ExecutionList executionList = new ExecutionList();
/**
* Constructor for use by subclasses.
*/
protected AbstractFuture() {}
/*
* Improve the documentation of when InterruptedException is thrown. Our
* behavior matches the JDK's, but the JDK's documentation is misleading.
*/
/**
* {@inheritDoc}
*
* <p>The default {@link AbstractFuture} implementation throws {@code
* InterruptedException} if the current thread is interrupted before or during
* the call, even if the value is already available.
*
* @throws InterruptedException if the current thread was interrupted before
* or during the call (optional but recommended).
* @throws CancellationException {@inheritDoc}
*/
@Override
public V get(long timeout, TimeUnit unit) throws InterruptedException,
TimeoutException, ExecutionException {
return sync.get(unit.toNanos(timeout));
}
/*
* Improve the documentation of when InterruptedException is thrown. Our
* behavior matches the JDK's, but the JDK's documentation is misleading.
*/
/**
* {@inheritDoc}
*
* <p>The default {@link AbstractFuture} implementation throws {@code
* InterruptedException} if the current thread is interrupted before or during
* the call, even if the value is already available.
*
* @throws InterruptedException if the current thread was interrupted before
* or during the call (optional but recommended).
* @throws CancellationException {@inheritDoc}
*/
@Override
public V get() throws InterruptedException, ExecutionException {
return sync.get();
}
@Override
public boolean isDone() {
return sync.isDone();
}
@Override
public boolean isCancelled() {
return sync.isCancelled();
}
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
if (!sync.cancel(mayInterruptIfRunning)) {
return false;
}
executionList.execute();
if (mayInterruptIfRunning) {
interruptTask();
}
return true;
}
/**
* Subclasses can override this method to implement interruption of the
* future's computation. The method is invoked automatically by a successful
* call to {@link #cancel(boolean) cancel(true)}.
*
* <p>The default implementation does nothing.
*
* @since 10.0
*/
protected void interruptTask() {
}
/**
* Returns true if this future was cancelled with {@code
* mayInterruptIfRunning} set to {@code true}.
*
* @since 14.0
*/
protected final boolean wasInterrupted() {
return sync.wasInterrupted();
}
/**
* {@inheritDoc}
*
* @since 10.0
*/
@Override
public void addListener(Runnable listener, Executor exec) {
executionList.add(listener, exec);
}
/**
* Subclasses should invoke this method to set the result of the computation
* to {@code value}. This will set the state of the future to
* {@link AbstractFuture.Sync#COMPLETED} and invoke the listeners if the
* state was successfully changed.
*
* @param value the value that was the result of the task.
* @return true if the state was successfully changed.
*/
protected boolean set(V value) {
boolean result = sync.set(value);
if (result) {
executionList.execute();
}
return result;
}
/**
* Subclasses should invoke this method to set the result of the computation
* to an error, {@code throwable}. This will set the state of the future to
* {@link AbstractFuture.Sync#COMPLETED} and invoke the listeners if the
* state was successfully changed.
*
* @param throwable the exception that the task failed with.
* @return true if the state was successfully changed.
*/
protected boolean setException(Throwable throwable) {
boolean result = sync.setException(throwable);
if (result) {
executionList.execute();
}
return result;
}
/**
* <p>Following the contract of {@link AbstractQueuedSynchronizer} we create a
* private subclass to hold the synchronizer. This synchronizer is used to
* implement the blocking and waiting calls as well as to handle state changes
* in a thread-safe manner. The current state of the future is held in the
* Sync state, and the lock is released whenever the state changes to
* {@link #COMPLETED}, {@link #CANCELLED}, or {@link #INTERRUPTED}
*
* <p>To avoid races between threads doing release and acquire, we transition
* to the final state in two steps. One thread will successfully CAS from
* RUNNING to COMPLETING, that thread will then set the result of the
* computation, and only then transition to COMPLETED, CANCELLED, or
* INTERRUPTED.
*
* <p>We don't use the integer argument passed between acquire methods so we
* pass around a -1 everywhere.
*/
static final class Sync<V> extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 0L;
/* Valid states. */
static final int RUNNING = 0;
static final int COMPLETING = 1;
static final int COMPLETED = 2;
static final int CANCELLED = 4;
static final int INTERRUPTED = 8;
private V value;
private Throwable exception;
/*
* Acquisition succeeds if the future is done, otherwise it fails.
*/
@Override
protected int tryAcquireShared(int ignored) {
if (isDone()) {
return 1;
}
return -1;
}
/*
* We always allow a release to go through, this means the state has been
* successfully changed and the result is available.
*/
@Override
protected boolean tryReleaseShared(int finalState) {
setState(finalState);
return true;
}
/**
* Blocks until the task is complete or the timeout expires. Throws a
* {@link TimeoutException} if the timer expires, otherwise behaves like
* {@link #get()}.
*/
V get(long nanos) throws TimeoutException, CancellationException,
ExecutionException, InterruptedException {
// Attempt to acquire the shared lock with a timeout.
if (!tryAcquireSharedNanos(-1, nanos)) {
throw new TimeoutException("Timeout waiting for task.");
}
return getValue();
}
/**
* Blocks until {@link #complete(Object, Throwable, int)} has been
* successfully called. Throws a {@link CancellationException} if the task
* was cancelled, or a {@link ExecutionException} if the task completed with
* an error.
*/
V get() throws CancellationException, ExecutionException,
InterruptedException {
// Acquire the shared lock allowing interruption.
acquireSharedInterruptibly(-1);
return getValue();
}
/**
* Implementation of the actual value retrieval. Will return the value
* on success, an exception on failure, a cancellation on cancellation, or
* an illegal state if the synchronizer is in an invalid state.
*/
private V getValue() throws CancellationException, ExecutionException {
int state = getState();
switch (state) {
case COMPLETED:
if (exception != null) {
throw new ExecutionException(exception);
} else {
return value;
}
case CANCELLED:
case INTERRUPTED:
throw cancellationExceptionWithCause(
"Task was cancelled.", exception);
default:
throw new IllegalStateException(
"Error, synchronizer in invalid state: " + state);
}
}
/**
* Checks if the state is {@link #COMPLETED}, {@link #CANCELLED}, or {@link
* INTERRUPTED}.
*/
boolean isDone() {
return (getState() & (COMPLETED | CANCELLED | INTERRUPTED)) != 0;
}
/**
* Checks if the state is {@link #CANCELLED} or {@link #INTERRUPTED}.
*/
boolean isCancelled() {
return (getState() & (CANCELLED | INTERRUPTED)) != 0;
}
/**
* Checks if the state is {@link #INTERRUPTED}.
*/
boolean wasInterrupted() {
return getState() == INTERRUPTED;
}
/**
* Transition to the COMPLETED state and set the value.
*/
boolean set(V v) {
return complete(v, null, COMPLETED);
}
/**
* Transition to the COMPLETED state and set the exception.
*/
boolean setException(Throwable t) {
return complete(null, t, COMPLETED);
}
/**
* Transition to the CANCELLED or INTERRUPTED state.
*/
boolean cancel(boolean interrupt) {
return complete(null, null, interrupt ? INTERRUPTED : CANCELLED);
}
/**
* Implementation of completing a task. Either {@code v} or {@code t} will
* be set but not both. The {@code finalState} is the state to change to
* from {@link #RUNNING}. If the state is not in the RUNNING state we
* return {@code false} after waiting for the state to be set to a valid
* final state ({@link #COMPLETED}, {@link #CANCELLED}, or {@link
* #INTERRUPTED}).
*
* @param v the value to set as the result of the computation.
* @param t the exception to set as the result of the computation.
* @param finalState the state to transition to.
*/
private boolean complete(V v, Throwable t,
int finalState) {
boolean doCompletion = compareAndSetState(RUNNING, COMPLETING);
if (doCompletion) {
// If this thread successfully transitioned to COMPLETING, set the value
// and exception and then release to the final state.
this.value = v;
// Don't actually construct a CancellationException until necessary.
this.exception = ((finalState & (CANCELLED | INTERRUPTED)) != 0)
? new CancellationException("Future.cancel() was called.") : t;
releaseShared(finalState);
} else if (getState() == COMPLETING) {
// If some other thread is currently completing the future, block until
// they are done so we can guarantee completion.
acquireShared(-1);
}
return doCompletion;
}
}
static final CancellationException cancellationExceptionWithCause(
String message, Throwable cause) {
CancellationException exception = new CancellationException(message);
exception.initCause(cause);
return exception;
}
}

View file

@ -0,0 +1,60 @@
/*
* Copyright (C) 2011 The Guava Authors
*
* 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 game.future;
/**
* {@link Error} variant of {@link java.util.concurrent.ExecutionException}. As
* with {@code ExecutionException}, the error's {@linkplain #getCause() cause}
* comes from a failed task, possibly run in another thread. That cause should
* itself be an {@code Error}; if not, use {@code ExecutionException} or {@link
* UncheckedExecutionException}. This allows the client code to continue to
* distinguish between exceptions and errors, even when they come from other
* threads.
*
* @author Chris Povirk
* @since 10.0
*/
class ExecutionError extends Error {
/**
* Creates a new instance with {@code null} as its detail message.
*/
protected ExecutionError() {}
/**
* Creates a new instance with the given detail message.
*/
protected ExecutionError(String message) {
super(message);
}
/**
* Creates a new instance with the given detail message and cause.
*/
public ExecutionError(String message, Error cause) {
super(message, cause);
}
/**
* Creates a new instance with the given cause.
*/
public ExecutionError(Error cause) {
super(cause);
}
private static final long serialVersionUID = 0;
}

View file

@ -0,0 +1,170 @@
/*
* Copyright (C) 2007 The Guava Authors
*
* 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 game.future;
import java.util.concurrent.Executor;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* <p>A list of listeners, each with an associated {@code Executor}, that
* guarantees that every {@code Runnable} that is {@linkplain #add added} will
* be executed after {@link #execute()} is called. Any {@code Runnable} added
* after the call to {@code execute} is still guaranteed to execute. There is no
* guarantee, however, that listeners will be executed in the order that they
* are added.
*
* <p>Exceptions thrown by a listener will be propagated up to the executor.
* Any exception thrown during {@code Executor.execute} (e.g., a {@code
* RejectedExecutionException} or an exception thrown by {@linkplain
* MoreExecutors#sameThreadExecutor inline execution}) will be caught and
* logged.
*
* @author Nishant Thakkar
* @author Sven Mawson
* @since 1.0
*/
final class ExecutionList {
// Logger to log exceptions caught when running runnables.
// @VisibleForTesting
static final Logger log = Logger.getLogger(ExecutionList.class.getName());
/**
* The runnable, executor pairs to execute. This acts as a stack threaded through the
* {@link RunnableExecutorPair#next} field.
*/
// @GuardedBy("this")
private RunnableExecutorPair runnables;
// @GuardedBy("this")
private boolean executed;
/** Creates a new, empty {@link ExecutionList}. */
public ExecutionList() {}
/**
* Adds the {@code Runnable} and accompanying {@code Executor} to the list of
* listeners to execute. If execution has already begun, the listener is
* executed immediately.
*
* <p>Note: For fast, lightweight listeners that would be safe to execute in
* any thread, consider {@link MoreExecutors#sameThreadExecutor}. For heavier
* listeners, {@code sameThreadExecutor()} carries some caveats: First, the
* thread that the listener runs in depends on whether the {@code
* ExecutionList} has been executed at the time it is added. In particular,
* listeners may run in the thread that calls {@code add}. Second, the thread
* that calls {@link #execute} may be an internal implementation thread, such
* as an RPC network thread, and {@code sameThreadExecutor()} listeners may
* run in this thread. Finally, during the execution of a {@code
* sameThreadExecutor} listener, all other registered but unexecuted
* listeners are prevented from running, even if those listeners are to run
* in other executors.
*/
public void add(Runnable runnable, Executor executor) {
// Fail fast on a null. We throw NPE here because the contract of
// Executor states that it throws NPE on null listener, so we propagate
// that contract up into the add method as well.
// Lock while we check state. We must maintain the lock while adding the
// new pair so that another thread can't run the list out from under us.
// We only add to the list if we have not yet started execution.
synchronized (this) {
if (!executed) {
runnables = new RunnableExecutorPair(runnable, executor, runnables);
return;
}
}
// Execute the runnable immediately. Because of scheduling this may end up
// getting called before some of the previously added runnables, but we're
// OK with that. If we want to change the contract to guarantee ordering
// among runnables we'd have to modify the logic here to allow it.
executeListener(runnable, executor);
}
/**
* Runs this execution list, executing all existing pairs in the order they
* were added. However, note that listeners added after this point may be
* executed before those previously added, and note that the execution order
* of all listeners is ultimately chosen by the implementations of the
* supplied executors.
*
* <p>This method is idempotent. Calling it several times in parallel is
* semantically equivalent to calling it exactly once.
*
* @since 10.0 (present in 1.0 as {@code run})
*/
public void execute() {
// Lock while we update our state so the add method above will finish adding
// any listeners before we start to run them.
RunnableExecutorPair list;
synchronized (this) {
if (executed) {
return;
}
executed = true;
list = runnables;
runnables = null; // allow GC to free listeners even if this stays around for a while.
}
// If we succeeded then list holds all the runnables we to execute. The pairs in the stack are
// in the opposite order from how they were added so we need to reverse the list to fulfill our
// contract.
// This is somewhat annoying, but turns out to be very fast in practice. Alternatively, we
// could drop the contract on the method that enforces this queue like behavior since depending
// on it is likely to be a bug anyway.
// N.B. All writes to the list and the next pointers must have happened before the above
// synchronized block, so we can iterate the list without the lock held here.
RunnableExecutorPair reversedList = null;
while (list != null) {
RunnableExecutorPair tmp = list;
list = list.next;
tmp.next = reversedList;
reversedList = tmp;
}
while (reversedList != null) {
executeListener(reversedList.runnable, reversedList.executor);
reversedList = reversedList.next;
}
}
/**
* Submits the given runnable to the given {@link Executor} catching and logging all
* {@linkplain RuntimeException runtime exceptions} thrown by the executor.
*/
private static void executeListener(Runnable runnable, Executor executor) {
try {
executor.execute(runnable);
} catch (RuntimeException e) {
// Log it and keep going, bad runnable and/or executor. Don't
// punish the other runnables if we're given a bad one. We only
// catch RuntimeException because we want Errors to propagate up.
log.log(Level.SEVERE, "RuntimeException while executing runnable "
+ runnable + " with executor " + executor, e);
}
}
private static final class RunnableExecutorPair {
final Runnable runnable;
final Executor executor;
RunnableExecutorPair next;
RunnableExecutorPair(Runnable runnable, Executor executor, RunnableExecutorPair next) {
this.runnable = runnable;
this.executor = executor;
this.next = next;
}
}
}

View file

@ -0,0 +1,43 @@
/*
* Copyright (C) 2011 The Guava Authors
*
* 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 game.future;
/**
* A callback for accepting the results of a {@link java.util.concurrent.Future}
* computation asynchronously.
*
* <p>To attach to a {@link ListenableFuture} use {@link Futures#addCallback}.
*
* @author Anthony Zana
* @since 10.0
*/
public interface FutureCallback<V> {
/**
* Invoked with the result of the {@code Future} computation when it is
* successful.
*/
void onSuccess(V result);
/**
* Invoked when a {@code Future} computation fails or is canceled.
*
* <p>If the future's {@link Future#get() get} method throws an {@link
* ExecutionException}, then the cause is passed to this method. Any other
* thrown object is passed unaltered.
*/
void onFailure(Throwable t);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,132 @@
/*
* Copyright (C) 2007 The Guava Authors
*
* 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 game.future;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
/**
* A {@link Future} that accepts completion listeners. Each listener has an
* associated executor, and it is invoked using this executor once the future's
* computation is {@linkplain Future#isDone() complete}. If the computation has
* already completed when the listener is added, the listener will execute
* immediately.
*
* <p>See the Guava User Guide article on <a href=
* "http://code.google.com/p/guava-libraries/wiki/ListenableFutureExplained">
* {@code ListenableFuture}</a>.
*
* <h3>Purpose</h3>
*
* <p>Most commonly, {@code ListenableFuture} is used as an input to another
* derived {@code Future}, as in {@link Futures#allAsList(Iterable)
* Futures.allAsList}. Many such methods are impossible to implement efficiently
* without listener support.
*
* <p>It is possible to call {@link #addListener addListener} directly, but this
* is uncommon because the {@code Runnable} interface does not provide direct
* access to the {@code Future} result. (Users who want such access may prefer
* {@link Futures#addCallback Futures.addCallback}.) Still, direct {@code
* addListener} calls are occasionally useful:<pre> {@code
* final String name = ...;
* inFlight.add(name);
* ListenableFuture<Result> future = service.query(name);
* future.addListener(new Runnable() {
* public void run() {
* processedCount.incrementAndGet();
* inFlight.remove(name);
* lastProcessed.set(name);
* logger.info("Done with {0}", name);
* }
* }, executor);}</pre>
*
* <h3>How to get an instance</h3>
*
* <p>Developers are encouraged to return {@code ListenableFuture} from their
* methods so that users can take advantages of the utilities built atop the
* class. The way that they will create {@code ListenableFuture} instances
* depends on how they currently create {@code Future} instances:
* <ul>
* <li>If they are returned from an {@code ExecutorService}, convert that
* service to a {@link ListeningExecutorService}, usually by calling {@link
* MoreExecutors#listeningDecorator(ExecutorService)
* MoreExecutors.listeningDecorator}. (Custom executors may find it more
* convenient to use {@link ListenableFutureTask} directly.)
* <li>If they are manually filled in by a call to {@link FutureTask#set} or a
* similar method, create a {@link SettableFuture} instead. (Users with more
* complex needs may prefer {@link AbstractFuture}.)
* </ul>
*
* <p>Occasionally, an API will return a plain {@code Future} and it will be
* impossible to change the return type. For this case, we provide a more
* expensive workaround in {@code JdkFutureAdapters}. However, when possible, it
* is more efficient and reliable to create a {@code ListenableFuture} directly.
*
* @author Sven Mawson
* @author Nishant Thakkar
* @since 1.0
*/
public interface ListenableFuture<V> extends Future<V> {
/**
* Registers a listener to be {@linkplain Executor#execute(Runnable) run} on
* the given executor. The listener will run when the {@code Future}'s
* computation is {@linkplain Future#isDone() complete} or, if the computation
* is already complete, immediately.
*
* <p>There is no guaranteed ordering of execution of listeners, but any
* listener added through this method is guaranteed to be called once the
* computation is complete.
*
* <p>Exceptions thrown by a listener will be propagated up to the executor.
* Any exception thrown during {@code Executor.execute} (e.g., a {@code
* RejectedExecutionException} or an exception thrown by {@linkplain
* MoreExecutors#sameThreadExecutor inline execution}) will be caught and
* logged.
*
* <p>Note: For fast, lightweight listeners that would be safe to execute in
* any thread, consider {@link MoreExecutors#sameThreadExecutor}. For heavier
* listeners, {@code sameThreadExecutor()} carries some caveats. For
* example, the listener may run on an unpredictable or undesirable thread:
*
* <ul>
* <li>If this {@code Future} is done at the time {@code addListener} is
* called, {@code addListener} will execute the listener inline.
* <li>If this {@code Future} is not yet done, {@code addListener} will
* schedule the listener to be run by the thread that completes this {@code
* Future}, which may be an internal system thread such as an RPC network
* thread.
* </ul>
*
* <p>Also note that, regardless of which thread executes the
* {@code sameThreadExecutor()} listener, all other registered but unexecuted
* listeners are prevented from running during its execution, even if those
* listeners are to run in other executors.
*
* <p>This is the most general listener interface. For common operations
* performed using listeners, see {@link
* game.future.Futures}. For a simplified but general
* listener interface, see {@link
* game.future.Futures#addCallback addCallback()}.
*
* @param listener the listener to run when the computation is complete
* @param executor the executor to run the listener in
* @throws NullPointerException if the executor or listener was null
* @throws RejectedExecutionException if we tried to execute the listener
* immediately but the executor rejected it.
*/
void addListener(Runnable listener, Executor executor);
}

View file

@ -0,0 +1,91 @@
/*
* Copyright (C) 2008 The Guava Authors
*
* 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 game.future;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import java.util.concurrent.FutureTask;
/**
* A {@link FutureTask} that also implements the {@link ListenableFuture}
* interface. Unlike {@code FutureTask}, {@code ListenableFutureTask} does not
* provide an overrideable {@link FutureTask#done() done()} method. For similar
* functionality, call {@link #addListener}.
*
* <p>
*
* @author Sven Mawson
* @since 1.0
*/
public class ListenableFutureTask<V> extends FutureTask<V>
implements ListenableFuture<V> {
// TODO(cpovirk): explore ways of making ListenableFutureTask final. There are
// some valid reasons such as BoundedQueueExecutorService to allow extends but it
// would be nice to make it final to avoid unintended usage.
// The execution list to hold our listeners.
private final ExecutionList executionList = new ExecutionList();
/**
* Creates a {@code ListenableFutureTask} that will upon running, execute the
* given {@code Callable}.
*
* @param callable the callable task
* @since 10.0
*/
public static <V> ListenableFutureTask<V> create(Callable<V> callable) {
return new ListenableFutureTask<V>(callable);
}
/**
* Creates a {@code ListenableFutureTask} that will upon running, execute the
* given {@code Runnable}, and arrange that {@code get} will return the
* given result on successful completion.
*
* @param runnable the runnable task
* @param result the result to return on successful completion. If you don't
* need a particular result, consider using constructions of the form:
* {@code ListenableFuture<?> f = ListenableFutureTask.create(runnable,
* null)}
* @since 10.0
*/
public static <V> ListenableFutureTask<V> create(
Runnable runnable, V result) {
return new ListenableFutureTask<V>(runnable, result);
}
ListenableFutureTask(Callable<V> callable) {
super(callable);
}
ListenableFutureTask(Runnable runnable, V result) {
super(runnable, result);
}
@Override
public void addListener(Runnable listener, Executor exec) {
executionList.add(listener, exec);
}
/**
* Internal implementation detail used to invoke the listeners.
*/
@Override
protected void done() {
executionList.execute();
}
}

View file

@ -0,0 +1,889 @@
/*
* Copyright (C) 2007 The Guava Authors
*
* 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 game.future;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.AbstractExecutorService;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* Factory and utility methods for {@link java.util.concurrent.Executor}, {@link
* ExecutorService}, and {@link ThreadFactory}.
*
* @author Eric Fellheimer
* @author Kyle Littlefield
* @author Justin Mahoney
* @since 3.0
*/
final class MoreExecutors {
private MoreExecutors() {}
/**
* Converts the given ThreadPoolExecutor into an ExecutorService that exits
* when the application is complete. It does so by using daemon threads and
* adding a shutdown hook to wait for their completion.
*
* <p>This is mainly for fixed thread pools.
* See {@link Executors#newFixedThreadPool(int)}.
*
* @param executor the executor to modify to make sure it exits when the
* application is finished
* @param terminationTimeout how long to wait for the executor to
* finish before terminating the JVM
* @param timeUnit unit of time for the time parameter
* @return an unmodifiable version of the input which will not hang the JVM
*/
// @Beta
// public static ExecutorService getExitingExecutorService(
// ThreadPoolExecutor executor, long terminationTimeout, TimeUnit timeUnit) {
// return new Application()
// .getExitingExecutorService(executor, terminationTimeout, timeUnit);
// }
/**
* Converts the given ScheduledThreadPoolExecutor into a
* ScheduledExecutorService that exits when the application is complete. It
* does so by using daemon threads and adding a shutdown hook to wait for
* their completion.
*
* <p>This is mainly for fixed thread pools.
* See {@link Executors#newScheduledThreadPool(int)}.
*
* @param executor the executor to modify to make sure it exits when the
* application is finished
* @param terminationTimeout how long to wait for the executor to
* finish before terminating the JVM
* @param timeUnit unit of time for the time parameter
* @return an unmodifiable version of the input which will not hang the JVM
*/
// @Beta
// public static ScheduledExecutorService getExitingScheduledExecutorService(
// ScheduledThreadPoolExecutor executor, long terminationTimeout, TimeUnit timeUnit) {
// return new Application()
// .getExitingScheduledExecutorService(executor, terminationTimeout, timeUnit);
// }
/**
* Add a shutdown hook to wait for thread completion in the given
* {@link ExecutorService service}. This is useful if the given service uses
* daemon threads, and we want to keep the JVM from exiting immediately on
* shutdown, instead giving these daemon threads a chance to terminate
* normally.
* @param service ExecutorService which uses daemon threads
* @param terminationTimeout how long to wait for the executor to finish
* before terminating the JVM
* @param timeUnit unit of time for the time parameter
*/
// @Beta
// public static void addDelayedShutdownHook(
// ExecutorService service, long terminationTimeout, TimeUnit timeUnit) {
// new Application()
// .addDelayedShutdownHook(service, terminationTimeout, timeUnit);
// }
/**
* Converts the given ThreadPoolExecutor into an ExecutorService that exits
* when the application is complete. It does so by using daemon threads and
* adding a shutdown hook to wait for their completion.
*
* <p>This method waits 120 seconds before continuing with JVM termination,
* even if the executor has not finished its work.
*
* <p>This is mainly for fixed thread pools.
* See {@link Executors#newFixedThreadPool(int)}.
*
* @param executor the executor to modify to make sure it exits when the
* application is finished
* @return an unmodifiable version of the input which will not hang the JVM
*/
// @Beta
// public static ExecutorService getExitingExecutorService(ThreadPoolExecutor executor) {
// return new Application().getExitingExecutorService(executor);
// }
/**
* Converts the given ThreadPoolExecutor into a ScheduledExecutorService that
* exits when the application is complete. It does so by using daemon threads
* and adding a shutdown hook to wait for their completion.
*
* <p>This method waits 120 seconds before continuing with JVM termination,
* even if the executor has not finished its work.
*
* <p>This is mainly for fixed thread pools.
* See {@link Executors#newScheduledThreadPool(int)}.
*
* @param executor the executor to modify to make sure it exits when the
* application is finished
* @return an unmodifiable version of the input which will not hang the JVM
*/
// @Beta
// public static ScheduledExecutorService getExitingScheduledExecutorService(
// ScheduledThreadPoolExecutor executor) {
// return new Application().getExitingScheduledExecutorService(executor);
// }
/** Represents the current application to register shutdown hooks. */
// @VisibleForTesting static class Application {
//
// final ExecutorService getExitingExecutorService(
// ThreadPoolExecutor executor, long terminationTimeout, TimeUnit timeUnit) {
// useDaemonThreadFactory(executor);
// ExecutorService service = Executors.unconfigurableExecutorService(executor);
// addDelayedShutdownHook(service, terminationTimeout, timeUnit);
// return service;
// }
//
// final ScheduledExecutorService getExitingScheduledExecutorService(
// ScheduledThreadPoolExecutor executor, long terminationTimeout, TimeUnit timeUnit) {
// useDaemonThreadFactory(executor);
// ScheduledExecutorService service = Executors.unconfigurableScheduledExecutorService(executor);
// addDelayedShutdownHook(service, terminationTimeout, timeUnit);
// return service;
// }
//
// final void addDelayedShutdownHook(
// final ExecutorService service, final long terminationTimeout, final TimeUnit timeUnit) {
// checkNotNull(service);
// checkNotNull(timeUnit);
// addShutdownHook(MoreExecutors.newThread("DelayedShutdownHook-for-" + service, new Runnable() {
// @Override
// public void run() {
// try {
// // We'd like to log progress and failures that may arise in the
// // following code, but unfortunately the behavior of logging
// // is undefined in shutdown hooks.
// // This is because the logging code installs a shutdown hook of its
// // own. See Cleaner class inside {@link LogManager}.
// service.shutdown();
// service.awaitTermination(terminationTimeout, timeUnit);
// } catch (InterruptedException ignored) {
// // We're shutting down anyway, so just ignore.
// }
// }
// }));
// }
//
// final ExecutorService getExitingExecutorService(ThreadPoolExecutor executor) {
// return getExitingExecutorService(executor, 120, TimeUnit.SECONDS);
// }
//
// final ScheduledExecutorService getExitingScheduledExecutorService(
// ScheduledThreadPoolExecutor executor) {
// return getExitingScheduledExecutorService(executor, 120, TimeUnit.SECONDS);
// }
//
// @VisibleForTesting void addShutdownHook(Thread hook) {
// Runtime.getRuntime().addShutdownHook(hook);
// }
// }
//
// private static void useDaemonThreadFactory(ThreadPoolExecutor executor) {
// executor.setThreadFactory(new ThreadFactoryBuilder()
// .setDaemon(true)
// .setThreadFactory(executor.getThreadFactory())
// .build());
// }
/**
* Creates an executor service that runs each task in the thread
* that invokes {@code execute/submit}, as in {@link CallerRunsPolicy} This
* applies both to individually submitted tasks and to collections of tasks
* submitted via {@code invokeAll} or {@code invokeAny}. In the latter case,
* tasks will run serially on the calling thread. Tasks are run to
* completion before a {@code Future} is returned to the caller (unless the
* executor has been shutdown).
*
* <p>Although all tasks are immediately executed in the thread that
* submitted the task, this {@code ExecutorService} imposes a small
* locking overhead on each task submission in order to implement shutdown
* and termination behavior.
*
* <p>The implementation deviates from the {@code ExecutorService}
* specification with regards to the {@code shutdownNow} method. First,
* "best-effort" with regards to canceling running tasks is implemented
* as "no-effort". No interrupts or other attempts are made to stop
* threads executing tasks. Second, the returned list will always be empty,
* as any submitted task is considered to have started execution.
* This applies also to tasks given to {@code invokeAll} or {@code invokeAny}
* which are pending serial execution, even the subset of the tasks that
* have not yet started execution. It is unclear from the
* {@code ExecutorService} specification if these should be included, and
* it's much easier to implement the interpretation that they not be.
* Finally, a call to {@code shutdown} or {@code shutdownNow} may result
* in concurrent calls to {@code invokeAll/invokeAny} throwing
* RejectedExecutionException, although a subset of the tasks may already
* have been executed.
*
* @since 10.0 (<a href="http://code.google.com/p/guava-libraries/wiki/Compatibility"
* >mostly source-compatible</a> since 3.0)
*/
public static SameThreadExecutorService sameThreadExecutor() {
return new SameThreadExecutorService();
}
// See sameThreadExecutor javadoc for behavioral notes.
private static class SameThreadExecutorService
extends AbstractExecutorService implements ExecutorService {
/**
* Lock used whenever accessing the state variables
* (runningTasks, shutdown, terminationCondition) of the executor
*/
private final Lock lock = new ReentrantLock();
/** Signaled after the executor is shutdown and running tasks are done */
private final Condition termination = lock.newCondition();
/*
* Conceptually, these two variables describe the executor being in
* one of three states:
* - Active: shutdown == false
* - Shutdown: runningTasks > 0 and shutdown == true
* - Terminated: runningTasks == 0 and shutdown == true
*/
private int runningTasks = 0;
private boolean shutdown = false;
@Override
public void execute(Runnable command) {
startTask();
try {
command.run();
} finally {
endTask();
}
}
@Override
public boolean isShutdown() {
lock.lock();
try {
return shutdown;
} finally {
lock.unlock();
}
}
@Override
public void shutdown() {
lock.lock();
try {
shutdown = true;
} finally {
lock.unlock();
}
}
// See sameThreadExecutor javadoc for unusual behavior of this method.
@Override
public List<Runnable> shutdownNow() {
shutdown();
return Collections.emptyList();
}
@Override
public boolean isTerminated() {
lock.lock();
try {
return shutdown && runningTasks == 0;
} finally {
lock.unlock();
}
}
@Override
public boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException {
long nanos = unit.toNanos(timeout);
lock.lock();
try {
for (;;) {
if (isTerminated()) {
return true;
} else if (nanos <= 0) {
return false;
} else {
nanos = termination.awaitNanos(nanos);
}
}
} finally {
lock.unlock();
}
}
/**
* Checks if the executor has been shut down and increments the running
* task count.
*
* @throws RejectedExecutionException if the executor has been previously
* shutdown
*/
private void startTask() {
lock.lock();
try {
if (isShutdown()) {
throw new RejectedExecutionException("Executor already shutdown");
}
runningTasks++;
} finally {
lock.unlock();
}
}
/**
* Decrements the running task count.
*/
private void endTask() {
lock.lock();
try {
runningTasks--;
if (isTerminated()) {
termination.signalAll();
}
} finally {
lock.unlock();
}
}
@Override protected final <T> ListenableFutureTask<T> newTaskFor(Runnable runnable, T value) {
return ListenableFutureTask.create(runnable, value);
}
@Override protected final <T> ListenableFutureTask<T> newTaskFor(Callable<T> callable) {
return ListenableFutureTask.create(callable);
}
@Override public ListenableFuture<?> submit(Runnable task) {
return (ListenableFuture<?>) super.submit(task);
}
@Override public <T> ListenableFuture<T> submit(Runnable task, T result) {
return (ListenableFuture<T>) super.submit(task, result);
}
@Override public <T> ListenableFuture<T> submit(Callable<T> task) {
return (ListenableFuture<T>) super.submit(task);
}
}
/**
* Creates an {@link ExecutorService} whose {@code submit} and {@code
* invokeAll} methods submit {@link ListenableFutureTask} instances to the
* given delegate executor. Those methods, as well as {@code execute} and
* {@code invokeAny}, are implemented in terms of calls to {@code
* delegate.execute}. All other methods are forwarded unchanged to the
* delegate. This implies that the returned {@code ListeningExecutorService}
* never calls the delegate's {@code submit}, {@code invokeAll}, and {@code
* invokeAny} methods, so any special handling of tasks must be implemented in
* the delegate's {@code execute} method or by wrapping the returned {@code
* ListeningExecutorService}.
*
* <p>If the delegate executor was already an instance of {@code
* ListeningExecutorService}, it is returned untouched, and the rest of this
* documentation does not apply.
*
* @since 10.0
*/
// public static ListeningExecutorService listeningDecorator(
// ExecutorService delegate) {
// return (delegate instanceof ListeningExecutorService)
// ? (ListeningExecutorService) delegate
// : (delegate instanceof ScheduledExecutorService)
// ? new ScheduledListeningDecorator((ScheduledExecutorService) delegate)
// : new ListeningDecorator(delegate);
// }
/**
* Creates a {@link ScheduledExecutorService} whose {@code submit} and {@code
* invokeAll} methods submit {@link ListenableFutureTask} instances to the
* given delegate executor. Those methods, as well as {@code execute} and
* {@code invokeAny}, are implemented in terms of calls to {@code
* delegate.execute}. All other methods are forwarded unchanged to the
* delegate. This implies that the returned {@code
* ListeningScheduledExecutorService} never calls the delegate's {@code
* submit}, {@code invokeAll}, and {@code invokeAny} methods, so any special
* handling of tasks must be implemented in the delegate's {@code execute}
* method or by wrapping the returned {@code
* ListeningScheduledExecutorService}.
*
* <p>If the delegate executor was already an instance of {@code
* ListeningScheduledExecutorService}, it is returned untouched, and the rest
* of this documentation does not apply.
*
* @since 10.0
*/
// public static ListeningScheduledExecutorService listeningDecorator(
// ScheduledExecutorService delegate) {
// return (delegate instanceof ListeningScheduledExecutorService)
// ? (ListeningScheduledExecutorService) delegate
// : new ScheduledListeningDecorator(delegate);
// }
// private static class ListeningDecorator
// extends AbstractListeningExecutorService {
// private final ExecutorService delegate;
//
// ListeningDecorator(ExecutorService delegate) {
// this.delegate = checkNotNull(delegate);
// }
//
// @Override
// public boolean awaitTermination(long timeout, TimeUnit unit)
// throws InterruptedException {
// return delegate.awaitTermination(timeout, unit);
// }
//
// @Override
// public boolean isShutdown() {
// return delegate.isShutdown();
// }
//
// @Override
// public boolean isTerminated() {
// return delegate.isTerminated();
// }
//
// @Override
// public void shutdown() {
// delegate.shutdown();
// }
//
// @Override
// public List<Runnable> shutdownNow() {
// return delegate.shutdownNow();
// }
//
// @Override
// public void execute(Runnable command) {
// delegate.execute(command);
// }
// }
//
// private static class ScheduledListeningDecorator
// extends ListeningDecorator implements ListeningScheduledExecutorService {
//
// final ScheduledExecutorService delegate;
//
// ScheduledListeningDecorator(ScheduledExecutorService delegate) {
// super(delegate);
// this.delegate = checkNotNull(delegate);
// }
//
// @Override
// public ListenableScheduledFuture<?> schedule(
// Runnable command, long delay, TimeUnit unit) {
// ListenableFutureTask<Void> task =
// ListenableFutureTask.create(command, null);
// ScheduledFuture<?> scheduled = delegate.schedule(task, delay, unit);
// return new ListenableScheduledTask<Void>(task, scheduled);
// }
//
// @Override
// public <V> ListenableScheduledFuture<V> schedule(
// Callable<V> callable, long delay, TimeUnit unit) {
// ListenableFutureTask<V> task = ListenableFutureTask.create(callable);
// ScheduledFuture<?> scheduled = delegate.schedule(task, delay, unit);
// return new ListenableScheduledTask<V>(task, scheduled);
// }
//
// @Override
// public ListenableScheduledFuture<?> scheduleAtFixedRate(
// Runnable command, long initialDelay, long period, TimeUnit unit) {
// NeverSuccessfulListenableFutureTask task =
// new NeverSuccessfulListenableFutureTask(command);
// ScheduledFuture<?> scheduled =
// delegate.scheduleAtFixedRate(task, initialDelay, period, unit);
// return new ListenableScheduledTask<Void>(task, scheduled);
// }
//
// @Override
// public ListenableScheduledFuture<?> scheduleWithFixedDelay(
// Runnable command, long initialDelay, long delay, TimeUnit unit) {
// NeverSuccessfulListenableFutureTask task =
// new NeverSuccessfulListenableFutureTask(command);
// ScheduledFuture<?> scheduled =
// delegate.scheduleWithFixedDelay(task, initialDelay, delay, unit);
// return new ListenableScheduledTask<Void>(task, scheduled);
// }
//
// private static final class ListenableScheduledTask<V>
// extends SimpleForwardingListenableFuture<V>
// implements ListenableScheduledFuture<V> {
//
// private final ScheduledFuture<?> scheduledDelegate;
//
// public ListenableScheduledTask(
// ListenableFuture<V> listenableDelegate,
// ScheduledFuture<?> scheduledDelegate) {
// super(listenableDelegate);
// this.scheduledDelegate = scheduledDelegate;
// }
//
// @Override
// public boolean cancel(boolean mayInterruptIfRunning) {
// boolean cancelled = super.cancel(mayInterruptIfRunning);
// if (cancelled) {
// // Unless it is cancelled, the delegate may continue being scheduled
// scheduledDelegate.cancel(mayInterruptIfRunning);
//
// // TODO(user): Cancel "this" if "scheduledDelegate" is cancelled.
// }
// return cancelled;
// }
//
// @Override
// public long getDelay(TimeUnit unit) {
// return scheduledDelegate.getDelay(unit);
// }
//
// @Override
// public int compareTo(Delayed other) {
// return scheduledDelegate.compareTo(other);
// }
// }
//
// private static final class NeverSuccessfulListenableFutureTask
// extends AbstractFuture<Void>
// implements Runnable {
// private final Runnable delegate;
//
// public NeverSuccessfulListenableFutureTask(Runnable delegate) {
// this.delegate = checkNotNull(delegate);
// }
//
// @Override public void run() {
// try {
// delegate.run();
// } catch (Throwable t) {
// setException(t);
// throw Throwables.propagate(t);
// }
// }
// }
// }
/*
* This following method is a modified version of one found in
* http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/test/tck/AbstractExecutorServiceTest.java?revision=1.30
* which contained the following notice:
*
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
* Other contributors include Andrew Wright, Jeffrey Hayes,
* Pat Fisher, Mike Judd.
*/
/**
* An implementation of {@link ExecutorService#invokeAny} for {@link ListeningExecutorService}
* implementations.
*/ // static <T> T invokeAnyImpl(ListeningExecutorService executorService,
// Collection<? extends Callable<T>> tasks, boolean timed, long nanos)
// throws InterruptedException, ExecutionException, TimeoutException {
// checkNotNull(executorService);
// int ntasks = tasks.size();
// checkArgument(ntasks > 0);
// List<Future<T>> futures = Lists.newArrayListWithCapacity(ntasks);
// BlockingQueue<Future<T>> futureQueue = Queues.newLinkedBlockingQueue();
//
// // For efficiency, especially in executors with limited
// // parallelism, check to see if previously submitted tasks are
// // done before submitting more of them. This interleaving
// // plus the exception mechanics account for messiness of main
// // loop.
//
// try {
// // Record exceptions so that if we fail to obtain any
// // result, we can throw the last exception we got.
// ExecutionException ee = null;
// long lastTime = timed ? System.nanoTime() : 0;
// Iterator<? extends Callable<T>> it = tasks.iterator();
//
// futures.add(submitAndAddQueueListener(executorService, it.next(), futureQueue));
// --ntasks;
// int active = 1;
//
// for (;;) {
// Future<T> f = futureQueue.poll();
// if (f == null) {
// if (ntasks > 0) {
// --ntasks;
// futures.add(submitAndAddQueueListener(executorService, it.next(), futureQueue));
// ++active;
// } else if (active == 0) {
// break;
// } else if (timed) {
// f = futureQueue.poll(nanos, TimeUnit.NANOSECONDS);
// if (f == null) {
// throw new TimeoutException();
// }
// long now = System.nanoTime();
// nanos -= now - lastTime;
// lastTime = now;
// } else {
// f = futureQueue.take();
// }
// }
// if (f != null) {
// --active;
// try {
// return f.get();
// } catch (ExecutionException eex) {
// ee = eex;
// } catch (RuntimeException rex) {
// ee = new ExecutionException(rex);
// }
// }
// }
//
// if (ee == null) {
// ee = new ExecutionException(null);
// }
// throw ee;
// } finally {
// for (Future<T> f : futures) {
// f.cancel(true);
// }
// }
// }
/**
* Submits the task and adds a listener that adds the future to {@code queue} when it completes.
*/
// private static <T> ListenableFuture<T> submitAndAddQueueListener(
// ListeningExecutorService executorService, Callable<T> task,
// final BlockingQueue<Future<T>> queue) {
// final ListenableFuture<T> future = executorService.submit(task);
// future.addListener(new Runnable() {
// @Override public void run() {
// queue.add(future);
// }
// }, MoreExecutors.sameThreadExecutor());
// return future;
// }
/**
* Returns a default thread factory used to create new threads.
*
* <p>On AppEngine, returns {@code ThreadManager.currentRequestThreadFactory()}.
* Otherwise, returns {@link Executors#defaultThreadFactory()}.
*
* @since 14.0
*/
// @Beta
// public static ThreadFactory platformThreadFactory() {
// if (!isAppEngine()) {
// return Executors.defaultThreadFactory();
// }
// try {
// return (ThreadFactory) Class.forName("com.google.appengine.api.ThreadManager")
// .getMethod("currentRequestThreadFactory")
// .invoke(null);
// } catch (IllegalAccessException e) {
// throw new RuntimeException("Couldn't invoke ThreadManager.currentRequestThreadFactory", e);
// } catch (ClassNotFoundException e) {
// throw new RuntimeException("Couldn't invoke ThreadManager.currentRequestThreadFactory", e);
// } catch (NoSuchMethodException e) {
// throw new RuntimeException("Couldn't invoke ThreadManager.currentRequestThreadFactory", e);
// } catch (InvocationTargetException e) {
// throw Throwables.propagate(e.getCause());
// }
// }
// private static boolean isAppEngine() {
// if (System.getProperty("com.google.appengine.runtime.environment") == null) {
// return false;
// }
// try {
// // If the current environment is null, we're not inside AppEngine.
// return Class.forName("com.google.apphosting.api.ApiProxy")
// .getMethod("getCurrentEnvironment")
// .invoke(null) != null;
// } catch (ClassNotFoundException e) {
// // If ApiProxy doesn't exist, we're not on AppEngine at all.
// return false;
// } catch (InvocationTargetException e) {
// // If ApiProxy throws an exception, we're not in a proper AppEngine environment.
// return false;
// } catch (IllegalAccessException e) {
// // If the method isn't accessible, we're not on a supported version of AppEngine;
// return false;
// } catch (NoSuchMethodException e) {
// // If the method doesn't exist, we're not on a supported version of AppEngine;
// return false;
// }
// }
/**
* Creates a thread using {@link #platformThreadFactory}, and sets its name to {@code name}
* unless changing the name is forbidden by the security manager.
*/
// static Thread newThread(String name, Runnable runnable) {
// checkNotNull(name);
// checkNotNull(runnable);
// Thread result = platformThreadFactory().newThread(runnable);
// try {
// result.setName(name);
// } catch (SecurityException e) {
// // OK if we can't set the name in this environment.
// }
// return result;
// }
// TODO(user): provide overloads for ListeningExecutorService? ListeningScheduledExecutorService?
// TODO(user): provide overloads that take constant strings? Function<Runnable, String>s to
// calculate names?
/**
* Creates an {@link Executor} that renames the {@link Thread threads} that its tasks run in.
*
* <p>The names are retrieved from the {@code nameSupplier} on the thread that is being renamed
* right before each task is run. The renaming is best effort, if a {@link SecurityManager}
* prevents the renaming then it will be skipped but the tasks will still execute.
*
*
* @param executor The executor to decorate
* @param nameSupplier The source of names for each task
*/
// static Executor renamingDecorator(final Executor executor, final Supplier<String> nameSupplier) {
// checkNotNull(executor);
// checkNotNull(nameSupplier);
// if (isAppEngine()) {
// // AppEngine doesn't support thread renaming, so don't even try
// return executor;
// }
// return new Executor() {
// @Override public void execute(Runnable command) {
// executor.execute(Callables.threadRenaming(command, nameSupplier));
// }
// };
// }
/**
* Creates an {@link ExecutorService} that renames the {@link Thread threads} that its tasks run
* in.
*
* <p>The names are retrieved from the {@code nameSupplier} on the thread that is being renamed
* right before each task is run. The renaming is best effort, if a {@link SecurityManager}
* prevents the renaming then it will be skipped but the tasks will still execute.
*
*
* @param service The executor to decorate
* @param nameSupplier The source of names for each task
*/
// static ExecutorService renamingDecorator(final ExecutorService service,
// final Supplier<String> nameSupplier) {
// checkNotNull(service);
// checkNotNull(nameSupplier);
// if (isAppEngine()) {
// // AppEngine doesn't support thread renaming, so don't even try.
// return service;
// }
// return new WrappingExecutorService(service) {
// @Override protected <T> Callable<T> wrapTask(Callable<T> callable) {
// return Callables.threadRenaming(callable, nameSupplier);
// }
// @Override protected Runnable wrapTask(Runnable command) {
// return Callables.threadRenaming(command, nameSupplier);
// }
// };
// }
/**
* Creates a {@link ScheduledExecutorService} that renames the {@link Thread threads} that its
* tasks run in.
*
* <p>The names are retrieved from the {@code nameSupplier} on the thread that is being renamed
* right before each task is run. The renaming is best effort, if a {@link SecurityManager}
* prevents the renaming then it will be skipped but the tasks will still execute.
*
*
* @param service The executor to decorate
* @param nameSupplier The source of names for each task
*/
// static ScheduledExecutorService renamingDecorator(final ScheduledExecutorService service,
// final Supplier<String> nameSupplier) {
// checkNotNull(service);
// checkNotNull(nameSupplier);
// if (isAppEngine()) {
// // AppEngine doesn't support thread renaming, so don't even try.
// return service;
// }
// return new WrappingScheduledExecutorService(service) {
// @Override protected <T> Callable<T> wrapTask(Callable<T> callable) {
// return Callables.threadRenaming(callable, nameSupplier);
// }
// @Override protected Runnable wrapTask(Runnable command) {
// return Callables.threadRenaming(command, nameSupplier);
// }
// };
// }
/**
* Shuts down the given executor gradually, first disabling new submissions and later cancelling
* existing tasks.
*
* <p>The method takes the following steps:
* <ol>
* <li>calls {@link ExecutorService#shutdown()}, disabling acceptance of new submitted tasks.
* <li>waits for half of the specified timeout.
* <li>if the timeout expires, it calls {@link ExecutorService#shutdownNow()}, cancelling
* pending tasks and interrupting running tasks.
* <li>waits for the other half of the specified timeout.
* </ol>
*
* <p>If, at any step of the process, the given executor is terminated or the calling thread is
* interrupted, the method may return without executing any remaining steps.
*
* @param service the {@code ExecutorService} to shut down
* @param timeout the maximum time to wait for the {@code ExecutorService} to terminate
* @param unit the time unit of the timeout argument
* @return {@code true) if the pool was terminated successfully, {@code false} if the
* {@code ExecutorService} could not terminate <b>or</b> the thread running this method
* is interrupted while waiting for the {@code ExecutorService} to terminate
* @since 17.0
*/
// @Beta
// public static boolean shutdownAndAwaitTermination(
// ExecutorService service, long timeout, TimeUnit unit) {
// checkNotNull(unit);
// // Disable new tasks from being submitted
// service.shutdown();
// try {
// long halfTimeoutNanos = TimeUnit.NANOSECONDS.convert(timeout, unit) / 2;
// // Wait for half the duration of the timeout for existing tasks to terminate
// if (!service.awaitTermination(halfTimeoutNanos, TimeUnit.NANOSECONDS)) {
// // Cancel currently executing tasks
// service.shutdownNow();
// // Wait the other half of the timeout for tasks to respond to being cancelled
// service.awaitTermination(halfTimeoutNanos, TimeUnit.NANOSECONDS);
// }
// } catch (InterruptedException ie) {
// // Preserve interrupt status
// Thread.currentThread().interrupt();
// // (Re-)Cancel if current thread also interrupted
// service.shutdownNow();
// }
// return service.isTerminated();
// }
}

View file

@ -0,0 +1,176 @@
/*
* Copyright (C) 2010 The Guava Authors
*
* 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 game.future;
import java.lang.Thread.UncaughtExceptionHandler;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicLong;
/**
* A ThreadFactory builder, providing any combination of these features:
* <ul>
* <li> whether threads should be marked as {@linkplain Thread#setDaemon daemon}
* threads
* <li> a {@linkplain ThreadFactoryBuilder#setNameFormat naming format}
* <li> a {@linkplain Thread#setPriority thread priority}
* <li> an {@linkplain Thread#setUncaughtExceptionHandler uncaught exception
* handler}
* <li> a {@linkplain ThreadFactory#newThread backing thread factory}
* </ul>
* <p>If no backing thread factory is provided, a default backing thread factory is
* used as if by calling {@code setThreadFactory(}{@link
* Executors#defaultThreadFactory()}{@code )}.
*
* @author Kurt Alfred Kluever
* @since 4.0
*/
public final class ThreadFactoryBuilder {
private String nameFormat = null;
private Boolean daemon = null;
private Integer priority = null;
private UncaughtExceptionHandler uncaughtExceptionHandler = null;
private ThreadFactory backingThreadFactory = null;
/**
* Creates a new {@link ThreadFactory} builder.
*/
public ThreadFactoryBuilder() {}
/**
* Sets the naming format to use when naming threads ({@link Thread#setName})
* which are created with this ThreadFactory.
*
* @param nameFormat a {@link String#format(String, Object...)}-compatible
* format String, to which a unique integer (0, 1, etc.) will be supplied
* as the single parameter. This integer will be unique to the built
* instance of the ThreadFactory and will be assigned sequentially. For
* example, {@code "rpc-pool-%d"} will generate thread names like
* {@code "rpc-pool-0"}, {@code "rpc-pool-1"}, {@code "rpc-pool-2"}, etc.
* @return this for the builder pattern
*/
public ThreadFactoryBuilder setNameFormat(String nameFormat) {
String.format(nameFormat, 0); // fail fast if the format is bad or null
this.nameFormat = nameFormat;
return this;
}
/**
* Sets daemon or not for new threads created with this ThreadFactory.
*
* @param daemon whether or not new Threads created with this ThreadFactory
* will be daemon threads
* @return this for the builder pattern
*/
public ThreadFactoryBuilder setDaemon(boolean daemon) {
this.daemon = daemon;
return this;
}
/**
* Sets the priority for new threads created with this ThreadFactory.
*
* @param priority the priority for new Threads created with this
* ThreadFactory
* @return this for the builder pattern
*/
// public ThreadFactoryBuilder setPriority(int priority) {
// Thread#setPriority() already checks for validity. These error messages
// are nicer though and will fail-fast.
// checkArgument(priority >= Thread.MIN_PRIORITY,
// "Thread priority (%s) must be >= %s", priority, Thread.MIN_PRIORITY);
// checkArgument(priority <= Thread.MAX_PRIORITY,
// "Thread priority (%s) must be <= %s", priority, Thread.MAX_PRIORITY);
// this.priority = priority;
// return this;
// }
/**
* Sets the {@link UncaughtExceptionHandler} for new threads created with this
* ThreadFactory.
*
* @param uncaughtExceptionHandler the uncaught exception handler for new
* Threads created with this ThreadFactory
* @return this for the builder pattern
*/
// public ThreadFactoryBuilder setUncaughtExceptionHandler(
// UncaughtExceptionHandler uncaughtExceptionHandler) {
// this.uncaughtExceptionHandler = checkNotNull(uncaughtExceptionHandler);
// return this;
// }
/**
* Sets the backing {@link ThreadFactory} for new threads created with this
* ThreadFactory. Threads will be created by invoking #newThread(Runnable) on
* this backing {@link ThreadFactory}.
*
* @param backingThreadFactory the backing {@link ThreadFactory} which will
* be delegated to during thread creation.
* @return this for the builder pattern
*
* @see MoreExecutors
*/
// public ThreadFactoryBuilder setThreadFactory(
// ThreadFactory backingThreadFactory) {
// this.backingThreadFactory = checkNotNull(backingThreadFactory);
// return this;
// }
/**
* Returns a new thread factory using the options supplied during the building
* process. After building, it is still possible to change the options used to
* build the ThreadFactory and/or build again. State is not shared amongst
* built instances.
*
* @return the fully constructed {@link ThreadFactory}
*/
public ThreadFactory build() {
return build(this);
}
private static ThreadFactory build(ThreadFactoryBuilder builder) {
final String nameFormat = builder.nameFormat;
final Boolean daemon = builder.daemon;
final Integer priority = builder.priority;
final UncaughtExceptionHandler uncaughtExceptionHandler =
builder.uncaughtExceptionHandler;
final ThreadFactory backingThreadFactory =
(builder.backingThreadFactory != null)
? builder.backingThreadFactory
: Executors.defaultThreadFactory();
final AtomicLong count = (nameFormat != null) ? new AtomicLong(0) : null;
return new ThreadFactory() {
@Override public Thread newThread(Runnable runnable) {
Thread thread = backingThreadFactory.newThread(runnable);
if (nameFormat != null) {
thread.setName(String.format(nameFormat, count.getAndIncrement()));
}
if (daemon != null) {
thread.setDaemon(daemon);
}
if (priority != null) {
thread.setPriority(priority);
}
if (uncaughtExceptionHandler != null) {
thread.setUncaughtExceptionHandler(uncaughtExceptionHandler);
}
return thread;
}
};
}
}

View file

@ -0,0 +1,65 @@
/*
* Copyright (C) 2011 The Guava Authors
*
* 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 game.future;
/**
* Unchecked variant of {@link java.util.concurrent.ExecutionException}. As with
* {@code ExecutionException}, the exception's {@linkplain #getCause() cause}
* comes from a failed task, possibly run in another thread.
*
* <p>{@code UncheckedExecutionException} is intended as an alternative to
* {@code ExecutionException} when the exception thrown by a task is an
* unchecked exception. However, it may also wrap a checked exception in some
* cases.
*
* <p>When wrapping an {@code Error} from another thread, prefer {@link
* ExecutionError}. When wrapping a checked exception, prefer {@code
* ExecutionException}.
*
* @author Charles Fry
* @since 10.0
*/
class UncheckedExecutionException extends RuntimeException {
/**
* Creates a new instance with {@code null} as its detail message.
*/
protected UncheckedExecutionException() {}
/**
* Creates a new instance with the given detail message.
*/
protected UncheckedExecutionException(String message) {
super(message);
}
/**
* Creates a new instance with the given detail message and cause.
*/
public UncheckedExecutionException(String message, Throwable cause) {
super(message, cause);
}
/**
* Creates a new instance with the given cause.
*/
public UncheckedExecutionException(Throwable cause) {
super(cause);
}
private static final long serialVersionUID = 0;
}