View Javadoc

    1   /*
    2    * Copyright 2009 Red Hat, Inc.
    3    *
    4    * Red Hat licenses this file to you under the Apache License, version 2.0
    5    * (the "License"); you may not use this file except in compliance with the
    6    * 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;
    17
    18  import org.jboss.netty.logging.InternalLogger;
    19  import org.jboss.netty.logging.InternalLoggerFactory;
    20
    21
    22  /**
    23   * A {@link Runnable} that changes the current thread name and reverts it back
    24   * when its execution ends.  To change the default thread names set by Netty,
    25   * use {@link #setThreadNameDeterminer(ThreadNameDeterminer)}.
    26   *
    27   * @author <a href="http://www.jboss.org/netty/">The Netty Project</a>
    28   * @author <a href="http://gleamynode.net/">Trustin Lee</a>
    29   *
    30   * @version $Rev: 2080 $, $Date: 2010-01-26 18:04:19 +0900 (Tue, 26 Jan 2010) $
    31   *
    32   * @apiviz.landmark
    33   * @apiviz.has org.jboss.netty.util.ThreadNameDeterminer oneway - -
    34   *
    35   */
    36  public class ThreadRenamingRunnable implements Runnable {
    37
    38      private static final InternalLogger logger =
    39          InternalLoggerFactory.getInstance(ThreadRenamingRunnable.class);
    40
    41      private static volatile ThreadNameDeterminer threadNameDeterminer =
    42          ThreadNameDeterminer.PROPOSED;
    43
    44      /**
    45       * Returns the {@link ThreadNameDeterminer} which overrides the proposed
    46       * new thread name.
    47       */
    48      public static ThreadNameDeterminer getThreadNameDeterminer() {
    49          return threadNameDeterminer;
    50      }
    51
    52      /**
    53       * Sets the {@link ThreadNameDeterminer} which overrides the proposed new
    54       * thread name.  Please note that the specified {@link ThreadNameDeterminer}
    55       * affects only new {@link ThreadRenamingRunnable}s; the existing instances
    56       * are not affected at all.  Therefore, you should make sure to call this
    57       * method at the earliest possible point (i.e. before any Netty worker
    58       * thread starts) for consistent thread naming.  Otherwise, you might see
    59       * the default thread names and the new names appear at the same time in
    60       * the full thread dump.
    61       */
    62      public static void setThreadNameDeterminer(ThreadNameDeterminer threadNameDeterminer) {
    63          if (threadNameDeterminer == null) {
    64              throw new NullPointerException("threadNameDeterminer");
    65          }
    66          ThreadRenamingRunnable.threadNameDeterminer = threadNameDeterminer;
    67      }
    68
    69      private final Runnable runnable;
    70      private final String proposedThreadName;
    71
    72      /**
    73       * Creates a new instance which wraps the specified {@code runnable}
    74       * and changes the thread name to the specified thread name when the
    75       * specified {@code runnable} is running.
    76       */
    77      public ThreadRenamingRunnable(Runnable runnable, String proposedThreadName) {
    78          if (runnable == null) {
    79              throw new NullPointerException("runnable");
    80          }
    81          if (proposedThreadName == null) {
    82              throw new NullPointerException("proposedThreadName");
    83          }
    84          this.runnable = runnable;
    85          this.proposedThreadName = proposedThreadName;
    86      }
    87
    88      public void run() {
    89          final Thread currentThread = Thread.currentThread();
    90          final String oldThreadName = currentThread.getName();
    91          final String newThreadName = getNewThreadName(oldThreadName);
    92
    93          // Change the thread name before starting the actual runnable.
    94          boolean renamed = false;
    95          if (!oldThreadName.equals(newThreadName)) {
    96              try {
    97                  currentThread.setName(newThreadName);
    98                  renamed = true;
    99              } catch (SecurityException e) {
    100                 logger.debug(
    101                         "Failed to rename a thread " +
    102                         "due to security restriction.", e);
    103             }
    104         }
    105
    106         // Run the actual runnable and revert the name back when it ends.
    107         try {
    108             runnable.run();
    109         } finally {
    110             if (renamed) {
    111                 // Revert the name back if the current thread was renamed.
    112                 // We do not check the exception here because we know it works.
    113                 currentThread.setName(oldThreadName);
    114             }
    115         }
    116     }
    117
    118     private String getNewThreadName(String currentThreadName) {
    119         String newThreadName = null;
    120
    121         try {
    122             newThreadName =
    123                 getThreadNameDeterminer().determineThreadName(
    124                         currentThreadName, proposedThreadName);
    125         } catch (Throwable t) {
    126             logger.warn("Failed to determine the thread name", t);
    127         }
    128
    129         return newThreadName == null? currentThreadName : newThreadName;
    130     }
    131 }