001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements.  See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership.  The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the
007     * "License"); you may not use this file except in compliance
008     * with the License.  You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    
019    package org.apache.hadoop.util;
020    
021    import com.google.common.annotations.VisibleForTesting;
022    import org.apache.commons.logging.Log;
023    import org.apache.commons.logging.LogFactory;
024    
025    import java.util.concurrent.ExecutorService;
026    import java.util.concurrent.TimeUnit;
027    
028    /**
029     * Helper class to shutdown {@link Thread}s and {@link ExecutorService}s.
030     */
031    public class ShutdownThreadsHelper {
032      private static Log LOG = LogFactory.getLog(ShutdownThreadsHelper.class);
033    
034      @VisibleForTesting
035      static final int SHUTDOWN_WAIT_MS = 3000;
036    
037      /**
038       * @param thread {@link Thread to be shutdown}
039       * @return <tt>true</tt> if the thread is successfully interrupted,
040       * <tt>false</tt> otherwise
041       * @throws InterruptedException
042       */
043      public static boolean shutdownThread(Thread thread) {
044        return shutdownThread(thread, SHUTDOWN_WAIT_MS);
045      }
046    
047      /**
048       * @param thread {@link Thread to be shutdown}
049       * @param timeoutInMilliSeconds time to wait for thread to join after being
050       *                              interrupted
051       * @return <tt>true</tt> if the thread is successfully interrupted,
052       * <tt>false</tt> otherwise
053       * @throws InterruptedException
054       */
055      public static boolean shutdownThread(Thread thread,
056                                        long timeoutInMilliSeconds) {
057        if (thread == null) {
058          return true;
059        }
060    
061        try {
062          thread.interrupt();
063          thread.join(timeoutInMilliSeconds);
064          return true;
065        } catch (InterruptedException ie) {
066          LOG.warn("Interrupted while shutting down thread - " + thread.getName());
067          return false;
068        }
069      }
070    
071      /**
072       * @param service {@link ExecutorService to be shutdown}
073       * @return <tt>true</tt> if the service is terminated,
074       * <tt>false</tt> otherwise
075       * @throws InterruptedException
076       */
077      public static boolean shutdownExecutorService(ExecutorService service)
078          throws InterruptedException {
079        return shutdownExecutorService(service, SHUTDOWN_WAIT_MS);
080      }
081    
082      /**
083       * @param service {@link ExecutorService to be shutdown}
084       * @param timeoutInMs time to wait for {@link
085       * ExecutorService#awaitTermination(long, java.util.concurrent.TimeUnit)}
086       *                    calls in milli seconds.
087       * @return <tt>true</tt> if the service is terminated,
088       * <tt>false</tt> otherwise
089       * @throws InterruptedException
090       */
091      public static boolean shutdownExecutorService(ExecutorService service,
092                                            long timeoutInMs)
093          throws InterruptedException {
094        if (service == null) {
095          return true;
096        }
097    
098        service.shutdown();
099        if (!service.awaitTermination(timeoutInMs, TimeUnit.MILLISECONDS)) {
100          service.shutdownNow();
101          return service.awaitTermination(timeoutInMs, TimeUnit.MILLISECONDS);
102        } else {
103          return true;
104        }
105      }
106    }