1 /* 2 * Copyright (C) 2010 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * 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, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.common.util.concurrent; 18 19 import static com.google.common.base.Preconditions.checkArgument; 20 import static com.google.common.base.Preconditions.checkNotNull; 21 22 import java.lang.Thread.UncaughtExceptionHandler; 23 import java.util.concurrent.Executors; 24 import java.util.concurrent.ThreadFactory; 25 import java.util.concurrent.atomic.AtomicLong; 26 27 /** 28 * A ThreadFactory builder, providing any combination of these features: 29 * <ul> 30 * <li> whether threads should be marked as {@linkplain Thread#setDaemon daemon} 31 * threads 32 * <li> a {@linkplain ThreadFactoryBuilder#setNameFormat naming format} 33 * <li> a {@linkplain Thread#setPriority thread priority} 34 * <li> an {@linkplain Thread#setUncaughtExceptionHandler uncaught exception 35 * handler} 36 * <li> a {@linkplain ThreadFactory#newThread backing thread factory} 37 * </ul> 38 * <p>If no backing thread factory is provided, a default backing thread factory is 39 * used as if by calling {@code setThreadFactory(}{@link 40 * Executors#defaultThreadFactory()}{@code )}. 41 * 42 * @author Kurt Alfred Kluever 43 * @since 4.0 44 */ 45 public final class ThreadFactoryBuilder { 46 private String nameFormat = null; 47 private Boolean daemon = null; 48 private Integer priority = null; 49 private UncaughtExceptionHandler uncaughtExceptionHandler = null; 50 private ThreadFactory backingThreadFactory = null; 51 52 /** 53 * Creates a new {@link ThreadFactory} builder. 54 */ ThreadFactoryBuilder()55 public ThreadFactoryBuilder() {} 56 57 /** 58 * Sets the naming format to use when naming threads ({@link Thread#setName}) 59 * which are created with this ThreadFactory. 60 * 61 * @param nameFormat a {@link String#format(String, Object...)}-compatible 62 * format String, to which a unique integer (0, 1, etc.) will be supplied 63 * as the single parameter. This integer will be unique to the built 64 * instance of the ThreadFactory and will be assigned sequentially. For 65 * example, {@code "rpc-pool-%d"} will generate thread names like 66 * {@code "rpc-pool-0"}, {@code "rpc-pool-1"}, {@code "rpc-pool-2"}, etc. 67 * @return this for the builder pattern 68 */ 69 @SuppressWarnings("ReturnValueIgnored") setNameFormat(String nameFormat)70 public ThreadFactoryBuilder setNameFormat(String nameFormat) { 71 String.format(nameFormat, 0); // fail fast if the format is bad or null 72 this.nameFormat = nameFormat; 73 return this; 74 } 75 76 /** 77 * Sets daemon or not for new threads created with this ThreadFactory. 78 * 79 * @param daemon whether or not new Threads created with this ThreadFactory 80 * will be daemon threads 81 * @return this for the builder pattern 82 */ setDaemon(boolean daemon)83 public ThreadFactoryBuilder setDaemon(boolean daemon) { 84 this.daemon = daemon; 85 return this; 86 } 87 88 /** 89 * Sets the priority for new threads created with this ThreadFactory. 90 * 91 * @param priority the priority for new Threads created with this 92 * ThreadFactory 93 * @return this for the builder pattern 94 */ setPriority(int priority)95 public ThreadFactoryBuilder setPriority(int priority) { 96 // Thread#setPriority() already checks for validity. These error messages 97 // are nicer though and will fail-fast. 98 checkArgument(priority >= Thread.MIN_PRIORITY, 99 "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 */ setUncaughtExceptionHandler( UncaughtExceptionHandler uncaughtExceptionHandler)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 */ setThreadFactory( ThreadFactory backingThreadFactory)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 */ build()145 public ThreadFactory build() { 146 return build(this); 147 } 148 build(ThreadFactoryBuilder builder)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 } 180