Class ExecutionSequencer.TaskNonReentrantExecutor

java.lang.Object
java.util.concurrent.atomic.AtomicReference<ExecutionSequencer.RunningState>
com.google.common.util.concurrent.ExecutionSequencer.TaskNonReentrantExecutor
All Implemented Interfaces:
Serializable, Runnable, Executor
Enclosing class:
ExecutionSequencer

private static final class ExecutionSequencer.TaskNonReentrantExecutor extends AtomicReference<ExecutionSequencer.RunningState> implements Executor, Runnable
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 Details

    • sequencer

      @CheckForNull ExecutionSequencer sequencer
      Used to update and read the latestTaskQueue field. Set to null once the runnable has been run or queued.
    • delegate

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

      @CheckForNull 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.
    • submitting

      @CheckForNull Thread submitting
      Thread that called execute(). Set in execute, cleared when delegate.execute() returns.
  • Constructor Details

  • Method Details

    • execute

      public void execute(Runnable task)
      Specified by:
      execute in interface Executor
    • run

      public void run()
      Specified by:
      run in interface Runnable
    • trySetStarted

      private boolean trySetStarted()
    • trySetCancelled

      private boolean trySetCancelled()