重写线程池ThreadFactory接口实现对线程异常的捕获
在开发过程中经常会用到线程池,但创建线程池的方法都比较简单,使用Executors来创建相应功能的线程池,常用的方法有这些。
1 2 3 4 5 |
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 4 |
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 28 |
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 54 |
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); } } } |