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 }