为何需要定制化的Thread Factory

当我们提交任务到Executor框架中时,一个线程会负责执行该任务。该线程有可能从线程池中分配,也有可能是按需创建。每一个Executor都对应一个ThreadFactory。如果我们在创建Executor的时候没有明确知道指定ThreadFactory,那么Executor会使用缺省的ThreadFactory.

我们来看一下JDK1.6中java.util.concurrent.Executors使用的DefaultThreadFactory.

/**
 * The default thread factory
 */
static class DefaultThreadFactory implements ThreadFactory {
    static final AtomicInteger poolNumber = new AtomicInteger(1);
    final ThreadGroup group;
    final AtomicInteger threadNumber = new AtomicInteger(1);
    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;
    }
}

既然Java concurrent包已经提供了缺省的Thread Factory,那么我们为何还要使用定制化的工厂呢?原因如下:

为了能够设置一个更有意义的线程名.
在DefaultThreadFactory中创建的线程名字格式为pool-m-thread-n, 也就是pool-1-thread-2,pool-2-thread-3,完全看不出该线程为何创建,在做什么事情。在调试、监控和查看日志时非常不便。

尤其是在分析thread dump时,线程名是确认线程由哪个Executor或thread pool创建和了解线程信息的重要线索。 在stack trace中,往往从头到尾都是JDK的类,很难知道这个线程是做什么的。一个有意义的线程名可以帮助我们迅速地定位问题。

"pool-7-thread-8011" id=29794 TIMED_WAITING
                       waiting on java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject@3a11cf61
                     at sun.misc.Unsafe.park (Unsafe.java) (native)
                     at java.util.concurrent.locks.LockSupport.parkNanos (LockSupport.java:196)
                     at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos (AbstractQueuedSynchronizer.java:2025)
                     at java.util.concurrent.DelayQueue.take (DelayQueue.java:164)
                     at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take (ScheduledThreadPoolExecutor.java:609)
                     at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take (ScheduledThreadPoolExecutor.java:602)
                     at java.util.concurrent.ThreadPoolExecutor.getTask (ThreadPoolExecutor.java:947)
                     at java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:907)
                     at java.lang.Thread.run (Thread.java:662)

自主选择线程类型:守护线程或用户线程

DefaultThreadFactory创建的线程类型均为用户线程,不能创建守护线程。

只要有用户线程尚在,JVM就不会退出。而一旦最后一个用户线程结束,即使还有守护线程运行,那么JVM也会退出。对于一些后台服务,我们更倾向于使用守护线程,比如Garbage Collector就是一个守护线程。

线程优先级
DefaultThreadFactory创建的线程优先级均为NORM_PRIORITY,高优先级的线程更容易得到调度,因此使用自定义的Thread Factory可以指定所创建线程的优先级。

处理未捕捉的异常
在执行一个任务时,线程可能会由于未捕获的异常而终止,默认处理是将异常打印到控制台。但这种处理方式有时并非你所想要的,存放如文件或者db会更合适。所以可以在自定义的Thread Factory中指定UncaughtExceptionHandler,发生异常时便会按照预期的逻辑执行。

下面是我为了能够指定更有意义的线程名所写的一个Thread Factory.

扫描二维码关注公众号,回复: 1651817 查看本文章

static class SelfDefinedThreadFactory implements ThreadFactory {
final AtomicInteger threadNumber = new AtomicInteger(1);
final String namePrefix;

    SelfDefinedThreadFactory(String namePrefix) {
         this.namePrefix = namePrefix+"-";
    }

    public Thread newThread(Runnable r) {
        Thread t = new Thread( r,namePrefix + threadNumber.getAndIncrement());
        if (t.isDaemon())
            t.setDaemon(true);
        if (t.getPriority() != Thread.NORM_PRIORITY)
            t.setPriority(Thread.NORM_PRIORITY);
        return t;
    }
}
private ExecutorService executor = Executors.newFixedThreadPool(50, new SelfDefinedThreadFactory("MessageProcessor"));

来源:http://blog.csdn.net/lovewithbeauty/article/details/50057469

猜你喜欢

转载自blog.csdn.net/zhufengzhuiri/article/details/79167703