回源码主页即时通讯网 - 即时通讯开发者社区!
1   /*
2    * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.
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  package com.baidu.fsg.uid.utils;
17  
18  import java.lang.Thread.UncaughtExceptionHandler;
19  import java.util.concurrent.ConcurrentHashMap;
20  import java.util.concurrent.ThreadFactory;
21  import java.util.concurrent.atomic.AtomicLong;
22  
23  import org.apache.commons.lang.ClassUtils;
24  import org.apache.commons.lang.StringUtils;
25  import org.slf4j.Logger;
26  import org.slf4j.LoggerFactory;
27  
28  /**
29   * Named thread in ThreadFactory. If there is no specified name for thread, it
30   * will auto detect using the invoker classname instead.
31   * 
32   * @author yutianbao
33   */
34  public class NamingThreadFactory implements ThreadFactory {
35      private static final Logger LOGGER = LoggerFactory.getLogger(NamingThreadFactory.class);
36  
37      /**
38       * Thread name pre
39       */
40      private String name;
41      /**
42       * Is daemon thread
43       */
44      private boolean daemon;
45      /**
46       * UncaughtExceptionHandler
47       */
48      private UncaughtExceptionHandler uncaughtExceptionHandler;
49      /**
50       * Sequences for multi thread name prefix
51       */
52      private final ConcurrentHashMap<String, AtomicLong> sequences;
53  
54      /**
55       * Constructors
56       */
57      public NamingThreadFactory() {
58          this(null, false, null);
59      }
60  
61      public NamingThreadFactory(String name) {
62          this(name, false, null);
63      }
64  
65      public NamingThreadFactory(String name, boolean daemon) {
66          this(name, daemon, null);
67      }
68  
69      public NamingThreadFactory(String name, boolean daemon, UncaughtExceptionHandler handler) {
70          this.name = name;
71          this.daemon = daemon;
72          this.uncaughtExceptionHandler = handler;
73          this.sequences = new ConcurrentHashMap<String, AtomicLong>();
74      }
75  
76      @Override
77      public Thread newThread(Runnable r) {
78          Thread thread = new Thread(r);
79          thread.setDaemon(this.daemon);
80  
81          // If there is no specified name for thread, it will auto detect using the invoker classname instead.
82          // Notice that auto detect may cause some performance overhead
83          String prefix = this.name;
84          if (StringUtils.isBlank(prefix)) {
85              prefix = getInvoker(2);
86          }
87          thread.setName(prefix + "-" + getSequence(prefix));
88  
89          // no specified uncaughtExceptionHandler, just do logging.
90          if (this.uncaughtExceptionHandler != null) {
91              thread.setUncaughtExceptionHandler(this.uncaughtExceptionHandler);
92          } else {
93              thread.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
94                  public void uncaughtException(Thread t, Throwable e) {
95                      LOGGER.error("unhandled exception in thread: " + t.getId() + ":" + t.getName(), e);
96                  }
97              });
98          }
99  
100         return thread;
101     }
102 
103     /**
104      * Get the method invoker's class name
105      * 
106      * @param depth
107      * @return
108      */
109     private String getInvoker(int depth) {
110         Exception e = new Exception();
111         StackTraceElement[] stes = e.getStackTrace();
112         if (stes.length > depth) {
113             return ClassUtils.getShortClassName(stes[depth].getClassName());
114         }
115         return getClass().getSimpleName();
116     }
117 
118     /**
119      * Get sequence for different naming prefix
120      * 
121      * @param invoker
122      * @return
123      */
124     private long getSequence(String invoker) {
125         AtomicLong r = this.sequences.get(invoker);
126         if (r == null) {
127             r = new AtomicLong(0);
128             AtomicLong previous = this.sequences.putIfAbsent(invoker, r);
129             if (previous != null) {
130                 r = previous;
131             }
132         }
133 
134         return r.incrementAndGet();
135     }
136 
137     /**
138      * Getters & Setters
139      */
140     public String getName() {
141         return name;
142     }
143 
144     public void setName(String name) {
145         this.name = name;
146     }
147 
148     public boolean isDaemon() {
149         return daemon;
150     }
151 
152     public void setDaemon(boolean daemon) {
153         this.daemon = daemon;
154     }
155 
156     public UncaughtExceptionHandler getUncaughtExceptionHandler() {
157         return uncaughtExceptionHandler;
158     }
159 
160     public void setUncaughtExceptionHandler(UncaughtExceptionHandler handler) {
161         this.uncaughtExceptionHandler = handler;
162     }
163 
164 }