001    /*
002     * Copyright (C) 2010 Google Inc.
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 com.google.common.annotations.Beta;
023    
024    import java.lang.Thread.UncaughtExceptionHandler;
025    import java.util.concurrent.Executors;
026    import java.util.concurrent.ThreadFactory;
027    import java.util.concurrent.atomic.AtomicLong;
028    
029    /**
030     * A ThreadFactory builder, providing any combination of these features:
031     * <ul>
032     * <li> whether threads should be marked as {@linkplain Thread#setDaemon daemon}
033     * threads
034     * <li> a {@linkplain ThreadFactoryBuilder#setNameFormat naming format}
035     * <li> a {@linkplain Thread#setPriority thread priority}
036     * <li> an {@linkplain Thread#setUncaughtExceptionHandler uncaught exception
037     * handler}
038     * <li> a {@linkplain ThreadFactory#newThread backing thread factory}
039     * </ul>
040     * If no backing thread factory is provided, a default backing thread factory is
041     * used as if by calling {@code setThreadFactory(}{@link
042     * Executors#defaultThreadFactory()}{@code )}.
043     *
044     * @author Kurt Alfred Kluever
045     * @since 4
046     */
047    @Beta
048    public final class ThreadFactoryBuilder {
049      private String nameFormat = null;
050      private Boolean daemon = null;
051      private Integer priority = null;
052      private UncaughtExceptionHandler uncaughtExceptionHandler = null;
053      private ThreadFactory backingThreadFactory = null;
054    
055      /**
056       * Creates a new {@link ThreadFactory} builder.
057       */
058      public ThreadFactoryBuilder() {}
059    
060      /**
061       * Sets the naming format to use when naming threads ({@link Thread#setName})
062       * which are created with this ThreadFactory.
063       *
064       * @param nameFormat a {@link String#format(String, Object...)}-compatible
065       *     format String, to which a unique integer (0, 1, etc.) will be supplied
066       *     as the single parameter. This integer will be unique to the built
067       *     instance of the ThreadFactory and will be assigned sequentially.
068       * @return this for the builder pattern
069       */
070      public ThreadFactoryBuilder setNameFormat(String nameFormat) {
071        String.format(nameFormat, 0); // fail fast if the format is bad or null
072        this.nameFormat = nameFormat;
073        return this;
074      }
075    
076      /**
077       * Sets daemon or not for new threads created with this ThreadFactory.
078       *
079       * @param daemon whether or not new Threads created with this ThreadFactory
080       *     will be daemon threads
081       * @return this for the builder pattern
082       */
083      public ThreadFactoryBuilder setDaemon(boolean daemon) {
084        this.daemon = daemon;
085        return this;
086      }
087    
088      /**
089       * Sets the priority for new threads created with this ThreadFactory.
090       *
091       * @param priority the priority for new Threads created with this
092       *     ThreadFactory
093       * @return this for the builder pattern
094       */
095      public ThreadFactoryBuilder setPriority(int priority) {
096        // Thread#setPriority() already checks for validity. These error messages
097        // are nicer though and will fail-fast.
098        checkArgument(priority >= Thread.MIN_PRIORITY,
099            "Thread priority (%s) must be >= %s", priority, Thread.MIN_PRIORITY);
100        checkArgument(priority <= Thread.MAX_PRIORITY,
101            "Thread priority (%s) must be <= %s", priority, Thread.MAX_PRIORITY);
102        this.priority = priority;
103        return this;
104      }
105    
106      /**
107       * Sets the {@link UncaughtExceptionHandler} for new threads created with this
108       * ThreadFactory.
109       *
110       * @param uncaughtExceptionHandler the uncaught exception handler for new
111       *     Threads created with this ThreadFactory
112       * @return this for the builder pattern
113       */
114      public ThreadFactoryBuilder setUncaughtExceptionHandler(
115          UncaughtExceptionHandler uncaughtExceptionHandler) {
116        this.uncaughtExceptionHandler = checkNotNull(uncaughtExceptionHandler);
117        return this;
118      }
119    
120      /**
121       * Sets the backing {@link ThreadFactory} for new threads created with this
122       * ThreadFactory. Threads will be created by invoking #newThread(Runnable) on
123       * this backing {@link ThreadFactory}.
124       *
125       * @param backingThreadFactory the backing {@link ThreadFactory} which will
126       *     be delegated to during thread creation.
127       * @return this for the builder pattern
128       *
129       * @see MoreExecutors
130       */
131      public ThreadFactoryBuilder setThreadFactory(
132          ThreadFactory backingThreadFactory) {
133        this.backingThreadFactory = checkNotNull(backingThreadFactory);
134        return this;
135      }
136    
137      /**
138       * Returns a new thread factory using the options supplied during the building
139       * process. After building, it is still possible to change the options used to
140       * build the ThreadFactory and/or build again. State is not shared amongst
141       * built instances.
142       *
143       * @return the fully constructed {@link ThreadFactory}
144       */
145      public ThreadFactory build() {
146        return build(this);
147      }
148    
149      private static ThreadFactory build(ThreadFactoryBuilder builder) {
150        final String nameFormat = builder.nameFormat;
151        final Boolean daemon = builder.daemon;
152        final Integer priority = builder.priority;
153        final UncaughtExceptionHandler uncaughtExceptionHandler =
154            builder.uncaughtExceptionHandler;
155        final ThreadFactory backingThreadFactory =
156            (builder.backingThreadFactory != null)
157            ? builder.backingThreadFactory
158            : Executors.defaultThreadFactory();
159        final AtomicLong count = (nameFormat != null) ? new AtomicLong(0) : null;
160        return new ThreadFactory() {
161          @Override public Thread newThread(Runnable runnable) {
162            Thread thread = backingThreadFactory.newThread(runnable);
163            if (nameFormat != null) {
164              thread.setName(String.format(nameFormat, count.getAndIncrement()));
165            }
166            if (daemon != null) {
167              thread.setDaemon(daemon);
168            }
169            if (priority != null) {
170              thread.setPriority(priority);
171            }
172            if (uncaughtExceptionHandler != null) {
173              thread.setUncaughtExceptionHandler(uncaughtExceptionHandler);
174            }
175            return thread;
176          }
177        };
178      }
179    }