View Javadoc

    1   /*
    2    * Copyright 2012 The Netty Project
    3    *
    4    * The Netty Project licenses this file to you under the Apache License,
    5    * version 2.0 (the "License"); you may not use this file except in compliance
    6    * with the License. You may obtain a copy of the License at:
    7    *
    8    *   http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    13   * License for the specific language governing permissions and limitations
    14   * under the License.
    15   */
    16  package org.jboss.netty.util.internal;
    17
    18  import java.util.concurrent.Executor;
    19  import java.util.concurrent.ExecutorService;
    20  import java.util.concurrent.TimeUnit;
    21
    22  /**
    23   * Shuts down a list of {@link Executor}s.  {@link #terminate(Executor...)} will
    24   * shut down all specified {@link ExecutorService}s immediately and wait for
    25   * their termination.  An {@link Executor} which is not an {@link ExecutorService}
    26   * will be ignored silently.
    27   */
    28  public final class ExecutorUtil {
    29
    30      /**
    31       * Returns {@code true} if and only if the specified {@code executor}
    32       * is an {@link ExecutorService} and is shut down.  Please note that this
    33       * method returns {@code false} if the specified {@code executor} is not an
    34       * {@link ExecutorService}.
    35       */
    36      public static boolean isShutdown(Executor executor) {
    37          if (executor instanceof ExecutorService) {
    38              if (((ExecutorService) executor).isShutdown()) {
    39                  return true;
    40              }
    41          }
    42          return false;
    43      }
    44
    45      /**
    46       * Shuts down the specified executors.
    47       */
    48      public static void terminate(Executor... executors) {
    49          terminate(DeadLockProofWorker.PARENT, executors);
    50      }
    51      /**
    52       * Shuts down the specified executors using the given {@link ThreadLocal} to check if there is a deadlock
    53       */
    54      public static void terminate(ThreadLocal<Executor> deadLockChecker, Executor... executors) {
    55          // Check nulls.
    56          if (executors == null) {
    57              throw new NullPointerException("executors");
    58          }
    59
    60          Executor[] executorsCopy = new Executor[executors.length];
    61          for (int i = 0; i < executors.length; i ++) {
    62              if (executors[i] == null) {
    63                  throw new NullPointerException("executors[" + i + "]");
    64              }
    65              executorsCopy[i] = executors[i];
    66          }
    67
    68          // Check dead lock.
    69          final Executor currentParent = deadLockChecker.get();
    70          if (currentParent != null) {
    71              for (Executor e: executorsCopy) {
    72                  if (e == currentParent) {
    73                      throw new IllegalStateException(
    74                              "An Executor cannot be shut down from the thread " +
    75                              "acquired from itself.  Please make sure you are " +
    76                              "not calling releaseExternalResources() from an " +
    77                              "I/O worker thread.");
    78                  }
    79              }
    80          }
    81
    82          // Shut down all executors.
    83          boolean interrupted = false;
    84          for (Executor e: executorsCopy) {
    85              if (!(e instanceof ExecutorService)) {
    86                  continue;
    87              }
    88
    89              ExecutorService es = (ExecutorService) e;
    90              for (;;) {
    91                  try {
    92                      es.shutdownNow();
    93                  } catch (SecurityException ex) {
    94                      // Running in a restricted environment - fall back.
    95                      try {
    96                          es.shutdown();
    97                      } catch (SecurityException ex2) {
    98                          // Running in a more restricted environment.
    99                          // Can't shut down this executor - skip to the next.
    100                         break;
    101                     } catch (NullPointerException ex2) {
    102                         // Some JDK throws NPE here, but shouldn't.
    103                     }
    104                 } catch (NullPointerException ex) {
    105                     // Some JDK throws NPE here, but shouldn't.
    106                 }
    107
    108                 try {
    109                     if (es.awaitTermination(100, TimeUnit.MILLISECONDS)) {
    110                         break;
    111                     }
    112                 } catch (InterruptedException ex) {
    113                     interrupted = true;
    114                 }
    115             }
    116         }
    117
    118         if (interrupted) {
    119             Thread.currentThread().interrupt();
    120         }
    121     }
    122
    123     private ExecutorUtil() {
    124         super();
    125     }
    126 }