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 }