Top Description Inners Fields Constructors Methods
com.google.common.util.concurrent

public final Class ExecutionSequencer

extends Object
Class Inheritance
Annotations
@ElementTypesAreNonnullByDefault
@J2ktIncompatible
Static Imports
com.google.common.base.Preconditions.checkNotNull, .Preconditions.checkState, com.google.common.util.concurrent.ExecutionSequencer.RunningState.CANCELLED, .ExecutionSequencer.RunningState.NOT_RUN, .ExecutionSequencer.RunningState.STARTED, .Futures.immediateCancelledFuture, .Futures.immediateFuture, .Futures.immediateVoidFuture, .MoreExecutors.directExecutor, java.util.Objects.requireNonNull

Serializes execution of tasks, somewhat like an "asynchronous synchronized block." Each enqueued callable will not be submitted to its associated executor until the previous callable has returned -- and, if the previous callable was an AsyncCallable, not until the Future it returned is done (successful, failed, or cancelled).

This class serializes execution of submitted tasks but not any listeners of those tasks.

Submitted tasks have a happens-before order as defined in the Java Language Specification. Tasks execute with the same happens-before order that the function calls to submit and submitAsync that submitted those tasks had.

This class has limited support for cancellation and other "early completions":

This class is similar to MoreExecutors#newSequentialExecutor. This class is different in a few ways:

If you don't need the features of this class, you may prefer newSequentialExecutor for its simplicity and ability to accommodate interruption.

Since
26.0

Nested and Inner Type Summary

Modifier and TypeClass and Description
pack-priv static enum
private static class
ExecutionSequencer.TaskNonReentrantExecutor

This class helps avoid a StackOverflowError when large numbers of tasks are submitted with MoreExecutors#directExecutor.

private static class
ExecutionSequencer.ThreadConfinedTaskQueue

This object is unsafely published, but avoids problematic races by relying exclusively on the identity equality of its Thread field so that the task field is only accessed by a single thread.

Field Summary

Modifier and TypeField and Description
private ExecutionSequencer.ThreadConfinedTaskQueue
private final AtomicReference<ListenableFuture<@Nullable Void>>
ref

This reference acts as a pointer tracking the head of a linked list of ListenableFutures.

Constructor Summary

AccessConstructor and Description
private

Method Summary

Modifier and TypeMethod and Description
public static ExecutionSequencer
create()

Creates a new instance.

public <T extends @Nullable Object> ListenableFuture<T>
submit(Callable<T> callable, Executor executor)

Enqueues a task to run when the previous task (if any) completes.

public <T extends @Nullable Object> ListenableFuture<T>
submitAsync(AsyncCallable<T> callable, Executor executor)

Enqueues a task to run when the previous task (if any) completes.

Inherited from java.lang.Object:
cloneequalsfinalizegetClasshashCodenotifynotifyAlltoStringwaitwaitwait

Field Detail

latestTaskQueueback to summary
private ExecutionSequencer.ThreadConfinedTaskQueue latestTaskQueue
refback to summary
private final AtomicReference<ListenableFuture<@Nullable Void>> ref

This reference acts as a pointer tracking the head of a linked list of ListenableFutures.

Constructor Detail

ExecutionSequencerback to summary
private ExecutionSequencer()

Method Detail

createback to summary
public static ExecutionSequencer create()

Creates a new instance.

submitback to summary
public <T extends @Nullable Object> ListenableFuture<T> submit(Callable<T> callable, Executor executor)

Enqueues a task to run when the previous task (if any) completes.

Cancellation does not propagate from the output future to a callable that has begun to execute, but if the output future is cancelled before Callable#call() is invoked, Callable#call() will not be invoked.

submitAsyncback to summary
public <T extends @Nullable Object> ListenableFuture<T> submitAsync(AsyncCallable<T> callable, Executor executor)

Enqueues a task to run when the previous task (if any) completes.

Cancellation does not propagate from the output future to the future returned from callable or a callable that has begun to execute, but if the output future is cancelled before AsyncCallable#call() is invoked, AsyncCallable#call() will not be invoked.

com.google.common.util.concurrent back to summary

pack-priv final Enum ExecutionSequencer.RunningState

extends Enum<ExecutionSequencer.RunningState>
Class Inheritance

Field Summary

Modifier and TypeField and Description
public static final ExecutionSequencer.RunningState
public static final ExecutionSequencer.RunningState
public static final ExecutionSequencer.RunningState

Constructor Summary

AccessConstructor and Description
private

Method Summary

Modifier and TypeMethod and Description
public static ExecutionSequencer.RunningState
public static ExecutionSequencer.RunningState[]
Inherited from java.lang.Enum:
clonecompareTodescribeConstableequalsfinalizegetDeclaringClasshashCodenameordinaltoStringvalueOf

Field Detail

CANCELLEDback to summary
public static final ExecutionSequencer.RunningState CANCELLED
NOT_RUNback to summary
public static final ExecutionSequencer.RunningState NOT_RUN
STARTEDback to summary
public static final ExecutionSequencer.RunningState STARTED

Constructor Detail

RunningStateback to summary
private RunningState()

Method Detail

valueOfback to summary
public static ExecutionSequencer.RunningState valueOf(String name)
valuesback to summary
public static ExecutionSequencer.RunningState[] values()
com.google.common.util.concurrent back to summary

private final Class ExecutionSequencer.TaskNonReentrantExecutor

extends AtomicReference<ExecutionSequencer.RunningState>
implements Executor, Runnable
Class Inheritance
All Implemented Interfaces
java.lang.Runnable, java.util.concurrent.Executor

This class helps avoid a StackOverflowError when large numbers of tasks are submitted with MoreExecutors#directExecutor. Normally, when the first future completes, all the other tasks would be called recursively. Here, we detect that the delegate executor is executing inline, and maintain a queue to dispatch tasks iteratively. There is one instance of this class per call to submit() or submitAsync(), and each instance supports only one call to execute().

This class would certainly be simpler and easier to reason about if it were built with ThreadLocal; however, ThreadLocal is not well optimized for the case where the ThreadLocal is non-static, and is initialized/removed frequently - this causes churn in the Thread specific hashmaps. Using a static ThreadLocal to avoid that overhead would mean that different ExecutionSequencer objects interfere with each other, which would be undesirable, in addition to increasing the memory footprint of every thread that interacted with it. In order to release entries in thread-specific maps when the ThreadLocal object itself is no longer referenced, ThreadLocal is usually implemented with a WeakReference, which can have negative performance properties; for example, calling WeakReference.get() on Android will block during an otherwise-concurrent GC cycle.

Field Summary

Modifier and TypeField and Description
pack-priv Executor
delegate

Executor the task was set to run on.

pack-priv ExecutionSequencer
sequencer

Used to update and read the latestTaskQueue field.

pack-priv Thread
submitting

Thread that called execute().

pack-priv Runnable
task

Set before calling delegate.execute(); set to null once run, so that it can be GCed; this object may live on after, if submitAsync returns an incomplete future.

Constructor Summary

AccessConstructor and Description
private

Method Summary

Modifier and TypeMethod and Description
public void
execute(Runnable
the runnable task
task
)

Implements java.util.concurrent.Executor.execute.

Executes the given command at some time in the future.
public void
run()

Implements java.lang.Runnable.run.

Runs this operation.
private boolean
private boolean
Inherited from java.util.concurrent.atomic.AtomicReference:
accumulateAndGetcompareAndExchangecompareAndExchangeAcquirecompareAndExchangeReleasecompareAndSetgetgetAcquiregetAndAccumulategetAndSetgetAndUpdategetOpaquegetPlainlazySetsetsetOpaquesetPlainsetReleasetoStringupdateAndGetweakCompareAndSetweakCompareAndSetAcquireweakCompareAndSetPlainweakCompareAndSetReleaseweakCompareAndSetVolatile

Field Detail

delegateback to summary
pack-priv Executor delegate

Executor the task was set to run on. Set to null when the task has been queued, run, or cancelled.

Annotations
@CheckForNull
sequencerback to summary
pack-priv ExecutionSequencer sequencer

Used to update and read the latestTaskQueue field. Set to null once the runnable has been run or queued.

Annotations
@CheckForNull
submittingback to summary
pack-priv Thread submitting

Thread that called execute(). Set in execute, cleared when delegate.execute() returns.

Annotations
@CheckForNull
taskback to summary
pack-priv Runnable task

Set before calling delegate.execute(); set to null once run, so that it can be GCed; this object may live on after, if submitAsync returns an incomplete future.

Annotations
@CheckForNull

Constructor Detail

TaskNonReentrantExecutorback to summary
private TaskNonReentrantExecutor(Executor delegate, ExecutionSequencer sequencer)

Method Detail

executeback to summary
public void execute(Runnable task)

Implements java.util.concurrent.Executor.execute.

Doc from java.util.concurrent.Executor.execute.

Executes the given command at some time in the future. The command may execute in a new thread, in a pooled thread, or in the calling thread, at the discretion of the Executor implementation.

Parameters
task:Runnable

the runnable task

Annotations
@Override
runback to summary
public void run()

Implements java.lang.Runnable.run.

Doc from java.lang.Runnable.run.

Runs this operation.

Annotations
@SuppressWarnings:ShortCircuitBoolean
@Override
trySetCancelledback to summary
private boolean trySetCancelled()
trySetStartedback to summary
private boolean trySetStarted()
com.google.common.util.concurrent back to summary

private final Class ExecutionSequencer.ThreadConfinedTaskQueue

extends Object
Class Inheritance
  • java.lang.Object
  • com.google.common.util.concurrent.ExecutionSequencer.ThreadConfinedTaskQueue

This object is unsafely published, but avoids problematic races by relying exclusively on the identity equality of its Thread field so that the task field is only accessed by a single thread.

Field Summary

Modifier and TypeField and Description
pack-priv Executor
nextExecutor

Only used by the thread associated with this object

pack-priv Runnable
nextTask

Only used by the thread associated with this object

pack-priv Thread
thread

This field is only used for identity comparisons with the current thread.

Constructor Summary

AccessConstructor and Description
private

Method Summary

Inherited from java.lang.Object:
cloneequalsfinalizegetClasshashCodenotifynotifyAlltoStringwaitwaitwait

Field Detail

nextExecutorback to summary
pack-priv Executor nextExecutor

Only used by the thread associated with this object

Annotations
@CheckForNull
nextTaskback to summary
pack-priv Runnable nextTask

Only used by the thread associated with this object

Annotations
@CheckForNull
threadback to summary
pack-priv Thread thread

This field is only used for identity comparisons with the current thread. Field assignments are atomic, but do not provide happens-before ordering; however:

  • If this field's value == currentThread, we know that it's up to date, because write operations in a thread always happen-before subsequent read operations in the same thread
  • If this field's value == null because of unsafe publication, we know that it isn't the object associated with our thread, because if it was the publication wouldn't have been unsafe and we'd have seen our thread as the value. This state is also why a new ThreadConfinedTaskQueue object must be created for each inline execution, because observing a null thread does not mean the object is safe to reuse.
  • If this field's value is some other thread object, we know that it's not our thread.
  • If this field's value == null because it originally belonged to another thread and that thread cleared it, we still know that it's not associated with our thread
  • If this field's value == null because it was associated with our thread and was cleared, we know that we're not executing inline any more
All the states where thread != currentThread are identical for our purposes, and so even though it's racy, we don't care which of those values we get, so no need to synchronize.
Annotations
@CheckForNull

Constructor Detail

ThreadConfinedTaskQueueback to summary
private ThreadConfinedTaskQueue()