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 * https://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 19 import java.lang.Thread.UncaughtExceptionHandler; 20 import java.util.Objects; 21 import java.util.concurrent.ExecutorService; 22 import java.util.concurrent.Executors; 23 import java.util.concurrent.ThreadFactory; 24 import java.util.concurrent.atomic.AtomicLong; 25 26 /** 27 * An implementation of the {@link ThreadFactory} interface that provides some 28 * configuration options for the threads it creates. 29 * <p> 30 * A {@link ThreadFactory} is used for instance by an {@link ExecutorService} to 31 * create the threads it uses for executing tasks. In many cases users do not 32 * have to care about a {@link ThreadFactory} because the default one used by an 33 * {@link ExecutorService} will do. However, if there are special requirements 34 * for the threads, a custom {@link ThreadFactory} has to be created. 35 * </p> 36 * <p> 37 * This class provides some frequently needed configuration options for the 38 * threads it creates. These are the following: 39 * </p> 40 * <ul> 41 * <li>A name pattern for the threads created by this factory can be specified. 42 * This is often useful if an application uses multiple executor services for 43 * different purposes. If the names of the threads used by these services have 44 * meaningful names, log output or exception traces can be much easier to read. 45 * Naming patterns are <em>format strings</em> as used by the {@code 46 * String.format()} method. The string can contain the place holder {@code %d} 47 * which will be replaced by the number of the current thread ({@code 48 * ThreadFactoryImpl} keeps a counter of the threads it has already created). 49 * For instance, the naming pattern {@code "My %d. worker thread"} will result 50 * in thread names like {@code "My 1. worker thread"}, {@code 51 * "My 2. worker thread"} and so on.</li> 52 * <li>A flag whether the threads created by this factory should be daemon 53 * threads. This can impact the exit behavior of the current Java application 54 * because the JVM shuts down if there are only daemon threads running.</li> 55 * <li>The priority of the thread. Here an integer value can be provided. The 56 * {@link Thread} class defines constants for valid ranges of priority 57 * values.</li> 58 * <li>The {@link UncaughtExceptionHandler} for the thread. This handler is 59 * called if an uncaught exception occurs within the thread.</li> 60 * </ul> 61 * <p> 62 * {@link BasicThreadFactory} wraps another thread factory which actually 63 * creates new threads. The configuration options are set on the threads created 64 * by the wrapped thread factory. On construction time the factory to be wrapped 65 * can be specified. If none is provided, a default {@link ThreadFactory} is 66 * used. 67 * </p> 68 * <p> 69 * Instances of {@link BasicThreadFactory} are not created directly, but the 70 * nested {@link Builder} class is used for this purpose. Using the builder only 71 * the configuration options an application is interested in need to be set. The 72 * following example shows how a {@link BasicThreadFactory} is created and 73 * installed in an {@link ExecutorService}: 74 * </p> 75 * 76 * <pre> 77 * // Create a factory that produces daemon threads with a naming pattern and 78 * // a priority 79 * BasicThreadFactory factory = new BasicThreadFactory.Builder() 80 * .namingPattern("workerthread-%d") 81 * .daemon(true) 82 * .priority(Thread.MAX_PRIORITY) 83 * .build(); 84 * // Create an executor service for single-threaded execution 85 * ExecutorService exec = Executors.newSingleThreadExecutor(factory); 86 * </pre> 87 * 88 * @since 3.0 89 */ 90 public class BasicThreadFactory implements ThreadFactory { 91 92 /** 93 * A <em>builder</em> class for creating instances of {@code 94 * BasicThreadFactory}. 95 * <p> 96 * Using this builder class instances of {@link BasicThreadFactory} can be 97 * created and initialized. The class provides methods that correspond to 98 * the configuration options supported by {@link BasicThreadFactory}. Method 99 * chaining is supported. Refer to the documentation of {@code 100 * BasicThreadFactory} for a usage example. 101 * </p> 102 */ 103 public static class Builder implements org.apache.commons.lang3.builder.Builder<BasicThreadFactory> { 104 105 /** The wrapped factory. */ 106 private ThreadFactory factory; 107 108 /** The uncaught exception handler. */ 109 private Thread.UncaughtExceptionHandler exceptionHandler; 110 111 /** The naming pattern. */ 112 private String namingPattern; 113 114 /** The priority. */ 115 private Integer priority; 116 117 /** The daemon flag. */ 118 private Boolean daemon; 119 120 /** 121 * Constructs a new instance. 122 * 123 * @deprecated Use {@link BasicThreadFactory#builder()}. 124 */ 125 @Deprecated 126 public Builder() { 127 // empty 128 } 129 130 /** 131 * Creates a new {@link BasicThreadFactory} with all configuration 132 * options that have been specified by calling methods on this builder. 133 * After creating the factory {@link #reset()} is called. 134 * 135 * @return the new {@link BasicThreadFactory} 136 */ 137 @Override 138 public BasicThreadFactory build() { 139 final BasicThreadFactory factory = new BasicThreadFactory(this); 140 reset(); 141 return factory; 142 } 143 144 /** 145 * Sets the daemon flag for the new {@link BasicThreadFactory} to {@code true} causing a new thread factory to create daemon threads. 146 * 147 * @return a reference to this {@link Builder} 148 * @since 3.18.0 149 */ 150 public Builder daemon() { 151 return daemon(true); 152 } 153 154 /** 155 * Sets the daemon flag for the new {@link BasicThreadFactory}. If this 156 * flag is set to <strong>true</strong> the new thread factory will create daemon 157 * threads. 158 * 159 * @param daemon the value of the daemon flag 160 * @return a reference to this {@link Builder} 161 */ 162 public Builder daemon(final boolean daemon) { 163 this.daemon = Boolean.valueOf(daemon); 164 return this; 165 } 166 167 /** 168 * Sets the naming pattern to be used by the new {@code 169 * BasicThreadFactory}. 170 * 171 * @param namingPattern the naming pattern (must not be <strong>null</strong>) 172 * @return a reference to this {@link Builder} 173 * @throws NullPointerException if the naming pattern is <strong>null</strong> 174 */ 175 public Builder namingPattern(final String namingPattern) { 176 this.namingPattern = Objects.requireNonNull(namingPattern, "pattern"); 177 return this; 178 } 179 180 /** 181 * Sets the priority for the threads created by the new {@code 182 * BasicThreadFactory}. 183 * 184 * @param priority the priority 185 * @return a reference to this {@link Builder} 186 */ 187 public Builder priority(final int priority) { 188 this.priority = Integer.valueOf(priority); 189 return this; 190 } 191 192 /** 193 * Resets this builder. All configuration options are set to default 194 * values. Note: If the {@link #build()} method was called, it is not 195 * necessary to call {@code reset()} explicitly because this is done 196 * automatically. 197 */ 198 public void reset() { 199 factory = null; 200 exceptionHandler = null; 201 namingPattern = null; 202 priority = null; 203 daemon = null; 204 } 205 206 /** 207 * Sets the uncaught exception handler for the threads created by the 208 * new {@link BasicThreadFactory}. 209 * 210 * @param exceptionHandler the {@link UncaughtExceptionHandler} (must not be 211 * <strong>null</strong>) 212 * @return a reference to this {@link Builder} 213 * @throws NullPointerException if the exception handler is <strong>null</strong> 214 */ 215 public Builder uncaughtExceptionHandler( 216 final Thread.UncaughtExceptionHandler exceptionHandler) { 217 this.exceptionHandler = Objects.requireNonNull(exceptionHandler, "handler"); 218 return this; 219 } 220 221 /** 222 * Sets the {@link ThreadFactory} to be wrapped by the new {@code 223 * BasicThreadFactory}. 224 * 225 * @param factory the wrapped {@link ThreadFactory} (must not be 226 * <strong>null</strong>) 227 * @return a reference to this {@link Builder} 228 * @throws NullPointerException if the passed in {@link ThreadFactory} 229 * is <strong>null</strong> 230 */ 231 public Builder wrappedFactory(final ThreadFactory factory) { 232 this.factory = Objects.requireNonNull(factory, "factory"); 233 return this; 234 } 235 } 236 237 /** 238 * Creates a new builder. 239 * 240 * @return a new builder. 241 * @since 3.18.0 242 */ 243 public static Builder builder() { 244 return new Builder(); 245 } 246 247 /** A counter for the threads created by this factory. */ 248 private final AtomicLong threadCounter; 249 250 /** Stores the wrapped factory. */ 251 private final ThreadFactory wrappedFactory; 252 253 /** Stores the uncaught exception handler. */ 254 private final Thread.UncaughtExceptionHandler uncaughtExceptionHandler; 255 256 /** Stores the naming pattern for newly created threads. */ 257 private final String namingPattern; 258 259 /** Stores the priority. */ 260 private final Integer priority; 261 262 /** Stores the daemon status flag. */ 263 private final Boolean daemon; 264 265 /** 266 * Creates a new instance of {@link ThreadFactory} and configures it 267 * from the specified {@link Builder} object. 268 * 269 * @param builder the {@link Builder} object 270 */ 271 private BasicThreadFactory(final Builder builder) { 272 wrappedFactory = builder.factory != null ? builder.factory : Executors.defaultThreadFactory(); 273 namingPattern = builder.namingPattern; 274 priority = builder.priority; 275 daemon = builder.daemon; 276 uncaughtExceptionHandler = builder.exceptionHandler; 277 threadCounter = new AtomicLong(); 278 } 279 280 /** 281 * Gets the daemon flag. This flag determines whether newly created 282 * threads should be daemon threads. If <strong>true</strong>, this factory object 283 * calls {@code setDaemon(true)} on the newly created threads. Result can be 284 * <strong>null</strong> if no daemon flag was provided at creation time. 285 * 286 * @return the daemon flag 287 */ 288 public final Boolean getDaemonFlag() { 289 return daemon; 290 } 291 292 /** 293 * Gets the naming pattern for naming newly created threads. Result can 294 * be <strong>null</strong> if no naming pattern was provided. 295 * 296 * @return the naming pattern 297 */ 298 public final String getNamingPattern() { 299 return namingPattern; 300 } 301 302 /** 303 * Gets the priority of the threads created by this factory. Result can 304 * be <strong>null</strong> if no priority was specified. 305 * 306 * @return the priority for newly created threads 307 */ 308 public final Integer getPriority() { 309 return priority; 310 } 311 312 /** 313 * Gets the number of threads this factory has already created. This 314 * class maintains an internal counter that is incremented each time the 315 * {@link #newThread(Runnable)} method is invoked. 316 * 317 * @return the number of threads created by this factory 318 */ 319 public long getThreadCount() { 320 return threadCounter.get(); 321 } 322 323 /** 324 * Gets the {@link UncaughtExceptionHandler} for the threads created by 325 * this factory. Result can be <strong>null</strong> if no handler was provided. 326 * 327 * @return the {@link UncaughtExceptionHandler} 328 */ 329 public final Thread.UncaughtExceptionHandler getUncaughtExceptionHandler() { 330 return uncaughtExceptionHandler; 331 } 332 333 /** 334 * Gets the wrapped {@link ThreadFactory}. This factory is used for 335 * actually creating threads. This method never returns <strong>null</strong>. If no 336 * {@link ThreadFactory} was passed when this object was created, a default 337 * thread factory is returned. 338 * 339 * @return the wrapped {@link ThreadFactory} 340 */ 341 public final ThreadFactory getWrappedFactory() { 342 return wrappedFactory; 343 } 344 345 /** 346 * Initializes the specified thread. This method is called by 347 * {@link #newThread(Runnable)} after a new thread has been obtained from 348 * the wrapped thread factory. It initializes the thread according to the 349 * options set for this factory. 350 * 351 * @param thread the thread to be initialized 352 */ 353 private void initializeThread(final Thread thread) { 354 if (getNamingPattern() != null) { 355 final Long count = Long.valueOf(threadCounter.incrementAndGet()); 356 thread.setName(String.format(getNamingPattern(), count)); 357 } 358 if (getUncaughtExceptionHandler() != null) { 359 thread.setUncaughtExceptionHandler(getUncaughtExceptionHandler()); 360 } 361 if (getPriority() != null) { 362 thread.setPriority(getPriority().intValue()); 363 } 364 if (getDaemonFlag() != null) { 365 thread.setDaemon(getDaemonFlag().booleanValue()); 366 } 367 } 368 369 /** 370 * Creates a new thread. This implementation delegates to the wrapped 371 * factory for creating the thread. Then, on the newly created thread the 372 * corresponding configuration options are set. 373 * 374 * @param runnable the {@link Runnable} to be executed by the new thread 375 * @return the newly created thread 376 */ 377 @Override 378 public Thread newThread(final Runnable runnable) { 379 final Thread thread = getWrappedFactory().newThread(runnable); 380 initializeThread(thread); 381 return thread; 382 } 383 }