    001    /*
    002     * Copyright (C) 2010 The Guava Authors
    003     *
    004     * Licensed under the Apache License, Version 2.0 (the "License");
    005     * you may not use this file except in compliance with the License.
    006     * You may obtain a copy of the License at
    007     *
    008     * http://www.apache.org/licenses/LICENSE-2.0
    009     *
    010     * Unless required by applicable law or agreed to in writing, software
    011     * distributed under the License is distributed on an "AS IS" BASIS,
    012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    013     * See the License for the specific language governing permissions and
    014     * limitations under the License.
    015     */
    016
    017    package com.google.common.util.concurrent;
    018
    019    import static com.google.common.base.Preconditions.checkArgument;
    020    import static com.google.common.base.Preconditions.checkNotNull;
    021
    022    import java.lang.Thread.UncaughtExceptionHandler;
    023    import java.util.concurrent.Executors;
    024    import java.util.concurrent.ThreadFactory;
    025    import java.util.concurrent.atomic.AtomicLong;
    026
    027    /**
    028     * A ThreadFactory builder, providing any combination of these features:
    029     * <ul>
    030     * <li> whether threads should be marked as {@linkplain Thread#setDaemon daemon}
    031     * threads
    032     * <li> a {@linkplain ThreadFactoryBuilder#setNameFormat naming format}
    033     * <li> a {@linkplain Thread#setPriority thread priority}
    034     * <li> an {@linkplain Thread#setUncaughtExceptionHandler uncaught exception
    035     * handler}
    036     * <li> a {@linkplain ThreadFactory#newThread backing thread factory}
    037     * </ul>
    038     * If no backing thread factory is provided, a default backing thread factory is
    039     * used as if by calling {@code setThreadFactory(}{@link
    040     * Executors#defaultThreadFactory()}{@code )}.
    041     *
    042     * @author Kurt Alfred Kluever
    043     * @since 4.0
    044     */
    045    public final class ThreadFactoryBuilder {
    046      private String nameFormat = null;
    047      private Boolean daemon = null;
    048      private Integer priority = null;
    049      private UncaughtExceptionHandler uncaughtExceptionHandler = null;
    050      private ThreadFactory backingThreadFactory = null;
    051
    052      /**
    053       * Creates a new {@link ThreadFactory} builder.
    054       */
    055      public ThreadFactoryBuilder() {}
    056
    057      /**
    058       * Sets the naming format to use when naming threads ({@link Thread#setName})
    059       * which are created with this ThreadFactory.
    060       *
    061       * @param nameFormat a {@link String#format(String, Object...)}-compatible
    062       *     format String, to which a unique integer (0, 1, etc.) will be supplied
    063       *     as the single parameter. This integer will be unique to the built
    064       *     instance of the ThreadFactory and will be assigned sequentially.
    065       * @return this for the builder pattern
    066       */
    067      public ThreadFactoryBuilder setNameFormat(String nameFormat) {
    068        String.format(nameFormat, 0); // fail fast if the format is bad or null
    069        this.nameFormat = nameFormat;
    070        return this;
    071      }
    072
    073      /**
    074       * Sets daemon or not for new threads created with this ThreadFactory.
    075       *
    076       * @param daemon whether or not new Threads created with this ThreadFactory
    077       *     will be daemon threads
    078       * @return this for the builder pattern
    079       */
    080      public ThreadFactoryBuilder setDaemon(boolean daemon) {
    081        this.daemon = daemon;
    082        return this;
    083      }
    084
    085      /**
    086       * Sets the priority for new threads created with this ThreadFactory.
    087       *
    088       * @param priority the priority for new Threads created with this
    089       *     ThreadFactory
    090       * @return this for the builder pattern
    091       */
    092      public ThreadFactoryBuilder setPriority(int priority) {
    093        // Thread#setPriority() already checks for validity. These error messages
    094        // are nicer though and will fail-fast.
    095        checkArgument(priority >= Thread.MIN_PRIORITY,
    096            "Thread priority (%s) must be >= %s", priority, Thread.MIN_PRIORITY);
    097        checkArgument(priority <= Thread.MAX_PRIORITY,
    098            "Thread priority (%s) must be <= %s", priority, Thread.MAX_PRIORITY);
    099        this.priority = priority;
    100        return this;
    101      }
    102
    103      /**
    104       * Sets the {@link UncaughtExceptionHandler} for new threads created with this
    105       * ThreadFactory.
    106       *
    107       * @param uncaughtExceptionHandler the uncaught exception handler for new
    108       *     Threads created with this ThreadFactory
    109       * @return this for the builder pattern
    110       */
    111      public ThreadFactoryBuilder setUncaughtExceptionHandler(
    112          UncaughtExceptionHandler uncaughtExceptionHandler) {
    113        this.uncaughtExceptionHandler = checkNotNull(uncaughtExceptionHandler);
    114        return this;
    115      }
    116
    117      /**
    118       * Sets the backing {@link ThreadFactory} for new threads created with this
    119       * ThreadFactory. Threads will be created by invoking #newThread(Runnable) on
    120       * this backing {@link ThreadFactory}.
    121       *
    122       * @param backingThreadFactory the backing {@link ThreadFactory} which will
    123       *     be delegated to during thread creation.
    124       * @return this for the builder pattern
    125       *
    126       * @see MoreExecutors
    127       */
    128      public ThreadFactoryBuilder setThreadFactory(
    129          ThreadFactory backingThreadFactory) {
    130        this.backingThreadFactory = checkNotNull(backingThreadFactory);
    131        return this;
    132      }
    133
    134      /**
    135       * Returns a new thread factory using the options supplied during the building
    136       * process. After building, it is still possible to change the options used to
    137       * build the ThreadFactory and/or build again. State is not shared amongst
    138       * built instances.
    139       *
    140       * @return the fully constructed {@link ThreadFactory}
    141       */
    142      public ThreadFactory build() {
    143        return build(this);
    144      }
    145
    146      private static ThreadFactory build(ThreadFactoryBuilder builder) {
    147        final String nameFormat = builder.nameFormat;
    148        final Boolean daemon = builder.daemon;
    149        final Integer priority = builder.priority;
    150        final UncaughtExceptionHandler uncaughtExceptionHandler =
    151            builder.uncaughtExceptionHandler;
    152        final ThreadFactory backingThreadFactory =
    153            (builder.backingThreadFactory != null)
    154            ? builder.backingThreadFactory
    155            : Executors.defaultThreadFactory();
    156        final AtomicLong count = (nameFormat != null) ? new AtomicLong(0) : null;
    157        return new ThreadFactory() {
    158          @Override public Thread newThread(Runnable runnable) {
    159            Thread thread = backingThreadFactory.newThread(runnable);
    160            if (nameFormat != null) {
    161              thread.setName(String.format(nameFormat, count.getAndIncrement()));
    162            }
    163            if (daemon != null) {
    164              thread.setDaemon(daemon);
    165            }
    166            if (priority != null) {
    167              thread.setPriority(priority);
    168            }
    169            if (uncaughtExceptionHandler != null) {
    170              thread.setUncaughtExceptionHandler(uncaughtExceptionHandler);
    171            }
    172            return thread;
    173          }
    174        };
    175      }
    176    }