为何需要定制化的Thread Factory?

来源:互联网 发布:知乎 和父母吵架 编辑:程序博客网 时间:2024/05/17 01:40

当我们提交任务到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,那么我们为何还要使用定制化的工厂呢?原因如下:

  1. 为了能够设置一个更有意义的线程名.
    在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)
  2. 自主选择线程类型:守护线程或用户线程

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

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

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

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

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

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"));
0 0
原创粉丝点击