Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * 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 com.google.common.util.concurrent;
 
 
 
 import  javax.annotation.Nullable;
 import  javax.annotation.concurrent.GuardedBy;

A list of listeners, each with an associated Executor, that guarantees that every Runnable that is added will be executed after execute() is called. Any Runnable added after the call to execute is still guaranteed to execute. There is no guarantee, however, that listeners will be executed in the order that they are added.

Exceptions thrown by a listener will be propagated up to the executor. Any exception thrown during Executor.execute (e.g., a RejectedExecutionException or an exception thrown by MoreExecutors.sameThreadExecutor inline execution) will be caught and logged.

Author(s):
Nishant Thakkar
Sven Mawson
Since:
1.0
 
 public 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 RunnableExecutorPair.next field.
 
   @GuardedBy("this")
   @GuardedBy("this")
   private boolean executed;

  
Creates a new, empty ExecutionList.
 
   public ExecutionList() {}

  
Adds the Runnable and accompanying Executor to the list of listeners to execute. If execution has already begun, the listener is executed immediately.

Note: For fast, lightweight listeners that would be safe to execute in any thread, consider MoreExecutors.sameThreadExecutor. For heavier listeners, sameThreadExecutor() carries some caveats: First, the thread that the listener runs in depends on whether the ExecutionList has been executed at the time it is added. In particular, listeners may run in the thread that calls add. Second, the thread that calls execute may be an internal implementation thread, such as an RPC network thread, and sameThreadExecutor() listeners may run in this thread. Finally, during the execution of a 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 runnableExecutor 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.
     Preconditions.checkNotNull(runnable"Runnable was null.");
     Preconditions.checkNotNull(executor"Executor was null.");
 
     // 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 (!) {
          = new RunnableExecutorPair(runnableexecutor);
         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(runnableexecutor);
  }

  
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.

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 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.
    synchronized (this) {
      if () {
        return;
      }
       = true;
      list = ;
       = 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.runnablereversedList.executor);
      reversedList = reversedList.next;
    }
  }

  
Submits the given runnable to the given Executor catching and logging all runtime exceptions thrown by the executor.
  private static void executeListener(Runnable runnableExecutor 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(."RuntimeException while executing runnable "
          + runnable + " with executor " + executore);
    }
  }
  private static final class RunnableExecutorPair {
    final Runnable runnable;
    final Executor executor;
    @Nullable RunnableExecutorPair next;
    RunnableExecutorPair(Runnable runnableExecutor executorRunnableExecutorPair next) {
      this. = runnable;
      this. = executor;
      this. = next;
    }
  }
New to GrepCode? Check out our FAQ X