BasicThreadFactory.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.apache.commons.lang3.concurrent;

  18. import java.lang.Thread.UncaughtExceptionHandler;
  19. import java.util.Objects;
  20. import java.util.concurrent.ExecutorService;
  21. import java.util.concurrent.Executors;
  22. import java.util.concurrent.ThreadFactory;
  23. import java.util.concurrent.atomic.AtomicLong;

  24. /**
  25.  * An implementation of the {@link ThreadFactory} interface that provides some
  26.  * configuration options for the threads it creates.
  27.  * <p>
  28.  * A {@link ThreadFactory} is used for instance by an {@link ExecutorService} to
  29.  * create the threads it uses for executing tasks. In many cases users do not
  30.  * have to care about a {@link ThreadFactory} because the default one used by an
  31.  * {@link ExecutorService} will do. However, if there are special requirements
  32.  * for the threads, a custom {@link ThreadFactory} has to be created.
  33.  * </p>
  34.  * <p>
  35.  * This class provides some frequently needed configuration options for the
  36.  * threads it creates. These are the following:
  37.  * </p>
  38.  * <ul>
  39.  * <li>A name pattern for the threads created by this factory can be specified.
  40.  * This is often useful if an application uses multiple executor services for
  41.  * different purposes. If the names of the threads used by these services have
  42.  * meaningful names, log output or exception traces can be much easier to read.
  43.  * Naming patterns are <em>format strings</em> as used by the {@code
  44.  * String.format()} method. The string can contain the place holder {@code %d}
  45.  * which will be replaced by the number of the current thread ({@code
  46.  * ThreadFactoryImpl} keeps a counter of the threads it has already created).
  47.  * For instance, the naming pattern {@code "My %d. worker thread"} will result
  48.  * in thread names like {@code "My 1. worker thread"}, {@code
  49.  * "My 2. worker thread"} and so on.</li>
  50.  * <li>A flag whether the threads created by this factory should be daemon
  51.  * threads. This can impact the exit behavior of the current Java application
  52.  * because the JVM shuts down if there are only daemon threads running.</li>
  53.  * <li>The priority of the thread. Here an integer value can be provided. The
  54.  * {@link Thread} class defines constants for valid ranges of priority
  55.  * values.</li>
  56.  * <li>The {@link UncaughtExceptionHandler} for the thread. This handler is
  57.  * called if an uncaught exception occurs within the thread.</li>
  58.  * </ul>
  59.  * <p>
  60.  * {@link BasicThreadFactory} wraps another thread factory which actually
  61.  * creates new threads. The configuration options are set on the threads created
  62.  * by the wrapped thread factory. On construction time the factory to be wrapped
  63.  * can be specified. If none is provided, a default {@link ThreadFactory} is
  64.  * used.
  65.  * </p>
  66.  * <p>
  67.  * Instances of {@link BasicThreadFactory} are not created directly, but the
  68.  * nested {@link Builder} class is used for this purpose. Using the builder only
  69.  * the configuration options an application is interested in need to be set. The
  70.  * following example shows how a {@link BasicThreadFactory} is created and
  71.  * installed in an {@link ExecutorService}:
  72.  * </p>
  73.  *
  74.  * <pre>
  75.  * // Create a factory that produces daemon threads with a naming pattern and
  76.  * // a priority
  77.  * BasicThreadFactory factory = new BasicThreadFactory.Builder()
  78.  *     .namingPattern(&quot;workerthread-%d&quot;)
  79.  *     .daemon(true)
  80.  *     .priority(Thread.MAX_PRIORITY)
  81.  *     .build();
  82.  * // Create an executor service for single-threaded execution
  83.  * ExecutorService exec = Executors.newSingleThreadExecutor(factory);
  84.  * </pre>
  85.  *
  86.  * @since 3.0
  87.  */
  88. public class BasicThreadFactory implements ThreadFactory {

  89.     /**
  90.      * A <em>builder</em> class for creating instances of {@code
  91.      * BasicThreadFactory}.
  92.      * <p>
  93.      * Using this builder class instances of {@link BasicThreadFactory} can be
  94.      * created and initialized. The class provides methods that correspond to
  95.      * the configuration options supported by {@link BasicThreadFactory}. Method
  96.      * chaining is supported. Refer to the documentation of {@code
  97.      * BasicThreadFactory} for a usage example.
  98.      * </p>
  99.      */
  100.     public static class Builder implements org.apache.commons.lang3.builder.Builder<BasicThreadFactory> {

  101.         /** The wrapped factory. */
  102.         private ThreadFactory factory;

  103.         /** The uncaught exception handler. */
  104.         private Thread.UncaughtExceptionHandler exceptionHandler;

  105.         /** The naming pattern. */
  106.         private String namingPattern;

  107.         /** The priority. */
  108.         private Integer priority;

  109.         /** The daemon flag. */
  110.         private Boolean daemon;

  111.         /**
  112.          * Constructs a new instance.
  113.          */
  114.         public Builder() {
  115.             // empty
  116.         }

  117.         /**
  118.          * Creates a new {@link BasicThreadFactory} with all configuration
  119.          * options that have been specified by calling methods on this builder.
  120.          * After creating the factory {@link #reset()} is called.
  121.          *
  122.          * @return the new {@link BasicThreadFactory}
  123.          */
  124.         @Override
  125.         public BasicThreadFactory build() {
  126.             final BasicThreadFactory factory = new BasicThreadFactory(this);
  127.             reset();
  128.             return factory;
  129.         }

  130.         /**
  131.          * Sets the daemon flag for the new {@link BasicThreadFactory}. If this
  132.          * flag is set to <b>true</b> the new thread factory will create daemon
  133.          * threads.
  134.          *
  135.          * @param daemon the value of the daemon flag
  136.          * @return a reference to this {@link Builder}
  137.          */
  138.         public Builder daemon(final boolean daemon) {
  139.             this.daemon = Boolean.valueOf(daemon);
  140.             return this;
  141.         }

  142.         /**
  143.          * Sets the naming pattern to be used by the new {@code
  144.          * BasicThreadFactory}.
  145.          *
  146.          * @param namingPattern the naming pattern (must not be <b>null</b>)
  147.          * @return a reference to this {@link Builder}
  148.          * @throws NullPointerException if the naming pattern is <b>null</b>
  149.          */
  150.         public Builder namingPattern(final String namingPattern) {
  151.             this.namingPattern = Objects.requireNonNull(namingPattern, "pattern");
  152.             return this;
  153.         }

  154.         /**
  155.          * Sets the priority for the threads created by the new {@code
  156.          * BasicThreadFactory}.
  157.          *
  158.          * @param priority the priority
  159.          * @return a reference to this {@link Builder}
  160.          */
  161.         public Builder priority(final int priority) {
  162.             this.priority = Integer.valueOf(priority);
  163.             return this;
  164.         }

  165.         /**
  166.          * Resets this builder. All configuration options are set to default
  167.          * values. Note: If the {@link #build()} method was called, it is not
  168.          * necessary to call {@code reset()} explicitly because this is done
  169.          * automatically.
  170.          */
  171.         public void reset() {
  172.             factory = null;
  173.             exceptionHandler = null;
  174.             namingPattern = null;
  175.             priority = null;
  176.             daemon = null;
  177.         }

  178.         /**
  179.          * Sets the uncaught exception handler for the threads created by the
  180.          * new {@link BasicThreadFactory}.
  181.          *
  182.          * @param exceptionHandler the {@link UncaughtExceptionHandler} (must not be
  183.          * <b>null</b>)
  184.          * @return a reference to this {@link Builder}
  185.          * @throws NullPointerException if the exception handler is <b>null</b>
  186.          */
  187.         public Builder uncaughtExceptionHandler(
  188.                 final Thread.UncaughtExceptionHandler exceptionHandler) {
  189.             this.exceptionHandler = Objects.requireNonNull(exceptionHandler, "handler");
  190.             return this;
  191.         }

  192.         /**
  193.          * Sets the {@link ThreadFactory} to be wrapped by the new {@code
  194.          * BasicThreadFactory}.
  195.          *
  196.          * @param factory the wrapped {@link ThreadFactory} (must not be
  197.          * <b>null</b>)
  198.          * @return a reference to this {@link Builder}
  199.          * @throws NullPointerException if the passed in {@link ThreadFactory}
  200.          * is <b>null</b>
  201.          */
  202.         public Builder wrappedFactory(final ThreadFactory factory) {
  203.             this.factory = Objects.requireNonNull(factory, "factory");
  204.             return this;
  205.         }
  206.     }

  207.     /** A counter for the threads created by this factory. */
  208.     private final AtomicLong threadCounter;

  209.     /** Stores the wrapped factory. */
  210.     private final ThreadFactory wrappedFactory;

  211.     /** Stores the uncaught exception handler. */
  212.     private final Thread.UncaughtExceptionHandler uncaughtExceptionHandler;

  213.     /** Stores the naming pattern for newly created threads. */
  214.     private final String namingPattern;

  215.     /** Stores the priority. */
  216.     private final Integer priority;

  217.     /** Stores the daemon status flag. */
  218.     private final Boolean daemon;

  219.     /**
  220.      * Creates a new instance of {@link ThreadFactory} and configures it
  221.      * from the specified {@link Builder} object.
  222.      *
  223.      * @param builder the {@link Builder} object
  224.      */
  225.     private BasicThreadFactory(final Builder builder) {
  226.         wrappedFactory = builder.factory != null ? builder.factory : Executors.defaultThreadFactory();
  227.         namingPattern = builder.namingPattern;
  228.         priority = builder.priority;
  229.         daemon = builder.daemon;
  230.         uncaughtExceptionHandler = builder.exceptionHandler;
  231.         threadCounter = new AtomicLong();
  232.     }

  233.     /**
  234.      * Gets the daemon flag. This flag determines whether newly created
  235.      * threads should be daemon threads. If <b>true</b>, this factory object
  236.      * calls {@code setDaemon(true)} on the newly created threads. Result can be
  237.      * <b>null</b> if no daemon flag was provided at creation time.
  238.      *
  239.      * @return the daemon flag
  240.      */
  241.     public final Boolean getDaemonFlag() {
  242.         return daemon;
  243.     }

  244.     /**
  245.      * Gets the naming pattern for naming newly created threads. Result can
  246.      * be <b>null</b> if no naming pattern was provided.
  247.      *
  248.      * @return the naming pattern
  249.      */
  250.     public final String getNamingPattern() {
  251.         return namingPattern;
  252.     }

  253.     /**
  254.      * Gets the priority of the threads created by this factory. Result can
  255.      * be <b>null</b> if no priority was specified.
  256.      *
  257.      * @return the priority for newly created threads
  258.      */
  259.     public final Integer getPriority() {
  260.         return priority;
  261.     }

  262.     /**
  263.      * Gets the number of threads this factory has already created. This
  264.      * class maintains an internal counter that is incremented each time the
  265.      * {@link #newThread(Runnable)} method is invoked.
  266.      *
  267.      * @return the number of threads created by this factory
  268.      */
  269.     public long getThreadCount() {
  270.         return threadCounter.get();
  271.     }

  272.     /**
  273.      * Gets the {@link UncaughtExceptionHandler} for the threads created by
  274.      * this factory. Result can be <b>null</b> if no handler was provided.
  275.      *
  276.      * @return the {@link UncaughtExceptionHandler}
  277.      */
  278.     public final Thread.UncaughtExceptionHandler getUncaughtExceptionHandler() {
  279.         return uncaughtExceptionHandler;
  280.     }

  281.     /**
  282.      * Gets the wrapped {@link ThreadFactory}. This factory is used for
  283.      * actually creating threads. This method never returns <b>null</b>. If no
  284.      * {@link ThreadFactory} was passed when this object was created, a default
  285.      * thread factory is returned.
  286.      *
  287.      * @return the wrapped {@link ThreadFactory}
  288.      */
  289.     public final ThreadFactory getWrappedFactory() {
  290.         return wrappedFactory;
  291.     }

  292.     /**
  293.      * Initializes the specified thread. This method is called by
  294.      * {@link #newThread(Runnable)} after a new thread has been obtained from
  295.      * the wrapped thread factory. It initializes the thread according to the
  296.      * options set for this factory.
  297.      *
  298.      * @param thread the thread to be initialized
  299.      */
  300.     private void initializeThread(final Thread thread) {
  301.         if (getNamingPattern() != null) {
  302.             final Long count = Long.valueOf(threadCounter.incrementAndGet());
  303.             thread.setName(String.format(getNamingPattern(), count));
  304.         }
  305.         if (getUncaughtExceptionHandler() != null) {
  306.             thread.setUncaughtExceptionHandler(getUncaughtExceptionHandler());
  307.         }
  308.         if (getPriority() != null) {
  309.             thread.setPriority(getPriority().intValue());
  310.         }
  311.         if (getDaemonFlag() != null) {
  312.             thread.setDaemon(getDaemonFlag().booleanValue());
  313.         }
  314.     }

  315.     /**
  316.      * Creates a new thread. This implementation delegates to the wrapped
  317.      * factory for creating the thread. Then, on the newly created thread the
  318.      * corresponding configuration options are set.
  319.      *
  320.      * @param runnable the {@link Runnable} to be executed by the new thread
  321.      * @return the newly created thread
  322.      */
  323.     @Override
  324.     public Thread newThread(final Runnable runnable) {
  325.         final Thread thread = getWrappedFactory().newThread(runnable);
  326.         initializeThread(thread);
  327.         return thread;
  328.     }
  329. }