重写线程池ThreadFactory接口实现对线程异常的捕获

algorain

重写线程池ThreadFactory接口实现对线程异常的捕获 在开发过程中经常会用到线程池,但创建线程池的方法都比较简单,使用Executors来创建相应功能的线程池,常用的方法有这些。

1
2
3
4
1、 Executors.newFixedThreadPool(int nThreads);创建固定大小(nThreads,大小不能超过int的最大值)的线程池
2、Executors.newSingleThreadExecutor():创建大小为1的固定线程池。
3、Executors.newCachedThreadPool();创建corePoolSize为0,最大线程数为整型的最大数,线程keepAliveTime为1分钟,缓存任务的队列为SynchronousQueue的线程池。
4、Executors.newScheduledThreadPool(int corePoolSize):创建corePoolSize大小的线程池。

创建过程中最关注的参数是corePoolSize,maximumPoolSize已用来配置核心线程数和最大线程数,而KeepAliveTime,BlockingQueue,threadFactory则常被忽略,或者说不设置也无妨正常使用,但在一些特别情况下还是需要特别设置这些参数来启动线程池,这次主要来说明ThreadFactory的用处和自定义的配置。 ThreadFactory是一个接口,用户可以自己实现接口,也可以使用默认实现的,其内部只有一个方法。

1
2
3
public interface ThreadFactory {
Thread newThread(Runnable r);
}

Executors中有默认实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
static class DefaultThreadFactory implements ThreadFactory {
private static final AtomicInteger poolNumber = new AtomicInteger(1);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;

DefaultThreadFactory() {
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() :
Thread.currentThread().getThreadGroup();
namePrefix = "pool-" +
poolNumber.getAndIncrement() +
"-thread-";
}

public Thread newThread(Runnable r) {
Thread t = new Thread(group, r,
namePrefix + threadNumber.getAndIncrement(),
0);
if (t.isDaemon())
t.setDaemon(false);
if (t.getPriority() != Thread.NORM_PRIORITY)
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
}

newThread方法中对线程的命名和守护线程和线程优先级进行配置,这里我们可以加入更多自定义的功能,比如处理线程异常的方法还有在线程启动时打印日志等等,让线程池的创建和启动变得灵活可控。当异常发生时,及时打印异常情况然后通知其他服务或者重启线程进行重试等,但UncaughtExceptionHandler方法仅适用于execute()方法往线程池提交任务的情况,如果是适用submit方法则由回调get方法时来处理异常。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
public class MyThreadFactory implements ThreadFactory {
static final Logger LOGGER= Logger.getAnonymousLogger();
private final UncaughtExceptionHandler ueh;
private final AtomicInteger threadNum = new AtomicInteger(1);
private final String namePrefix;

public MyThreadFactory() {
this(new LoggingUncaughtExceptionHandler(),”threadFactory”);
}

public MyThreadFactory(UncaughtExceptionHandler ueh, String namePrefix) {
this.ueh = ueh;
this.namePrefix = namePrefix;
}

protected Thread doMakeThread(final Runnable r){
return new Thread(r){
@Override
public String toString() {
ThreadGroup group = getThreadGroup();
String groupName = null == group?””:group.getName();
return getClass().getSimpleName() + “[“+getName()+”,”+getId()+”,”+groupName+”]@“+hashCode();
}
};
}

@Override
public Thread newThread(Runnable r) {
Thread t = doMakeThread(r);
t.setUncaughtExceptionHandler(ueh);
t.setName(namePrefix + “-“ +threadNum.getAndIncrement());
if (t.isDaemon()){
t.setDaemon(false);
}
if (t.getPriority() != Thread.NORM_PRIORITY){
t.setPriority(Thread.NORM_PRIORITY);
}
if (LOGGER.isLoggable(Level.FINE)){
LOGGER.fine(“new thread created”+t);
}
return t;
}
static class LoggingUncaughtExceptionHandler implements UncaughtExceptionHandler{

@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println(“error”);
LOGGER.log(Level.SEVERE,t+”terminated:”,e);
}
}

}

  • Title: 重写线程池ThreadFactory接口实现对线程异常的捕获
  • Author: algorain
  • Created at: 2021-07-16 13:39:32
  • Updated at: 2023-05-14 21:39:50
  • Link: http://www.rain1024.com/2021/07/16/重写线程池threadfactory接口实现对线程异常的捕获/
  • License: This work is licensed under CC BY-NC-SA 4.0.
 Comments
On this page
重写线程池ThreadFactory接口实现对线程异常的捕获