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

  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"));
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值