1 /**
2 * Copyright 2008 Atlassian Pty Ltd
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.atlassian.util.concurrent;
18
19 import static com.atlassian.util.concurrent.Assertions.isTrue;
20 import static com.atlassian.util.concurrent.Assertions.notNull;
21
22 import java.util.concurrent.ThreadFactory;
23 import java.util.concurrent.atomic.AtomicInteger;
24
25 /**
26 * Factory for creating {@link ThreadFactory} instances. All factory
27 * implementations produce named threads to give good stack-traces.
28 */
29 public class ThreadFactories {
30 public enum Type {
31 DAEMON(true), USER(false);
32
33 final boolean isDaemon;
34
35 Type(final boolean isDaemon) {
36 this.isDaemon = isDaemon;
37 }
38 }
39
40 /**
41 * Get a {@link ThreadFactory} with the required name prefix. The produced
42 * threads are user threads and have normal priority.
43 *
44 * @param name the prefix to use for naming the threads.
45 * @return a configured {@link ThreadFactory}
46 */
47 public static ThreadFactory namedThreadFactory(@NotNull final String name) {
48 return new Default(name, Type.USER, Thread.NORM_PRIORITY);
49 }
50
51 /**
52 * Get a {@link ThreadFactory} with the required name prefix and type (user
53 * or daemon). The produced threads have normal priority.
54 *
55 * @param name the prefix to use for naming the threads.
56 * @param type whether they are User or Daemon threads.
57 * @return a configured {@link ThreadFactory}
58 */
59 public static ThreadFactory namedThreadFactory(@NotNull final String name, @NotNull final Type type) {
60 return new Default(name, type, Thread.NORM_PRIORITY);
61 }
62
63 /**
64 * Get a {@link ThreadFactory} with the required name prefix, type and
65 * priority.
66 *
67 * @param name the prefix to use for naming the threads.
68 * @param type whether they are User or Daemon threads.
69 * @param priority the thread priority, must not be lower than
70 * {@link Thread#MIN_PRIORITY} or greater than {@link Thread#MAX_PRIORITY}
71 * @return a configured {@link ThreadFactory}
72 */
73 public static ThreadFactory namedThreadFactory(@NotNull final String name, @NotNull final Type type, final int priority) {
74 return new Default(name, type, priority);
75 }
76
77 private ThreadFactories() {
78 throw new AssertionError("cannot instantiate!");
79 }
80
81 static class Default implements ThreadFactory {
82 final ThreadGroup group;
83 final AtomicInteger threadNumber = new AtomicInteger(1);
84 final String namePrefix;
85 final Type type;
86 final int priority;
87
88 Default(final String name, final Type type, final int priority) {
89 notNull("name", name);
90 notNull("type", type);
91 isTrue("priority too low", priority >= Thread.MIN_PRIORITY);
92 isTrue("priority too high", priority <= Thread.MAX_PRIORITY);
93 final SecurityManager securityManager = System.getSecurityManager();
94 final ThreadGroup parent = (securityManager != null) ? securityManager.getThreadGroup() : Thread.currentThread().getThreadGroup();
95 group = new ThreadGroup(parent, name);
96 namePrefix = name + ":thread-";
97 this.type = type;
98 this.priority = priority;
99 }
100
101 public Thread newThread(final Runnable r) {
102 final Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0);
103 t.setDaemon(type.isDaemon);
104 t.setPriority(priority);
105 return t;
106 }
107 }
108 }