线程池中线程命名+ListenableFuture使用

2019-10-16  本文已影响0人  今年五年级

线程池中线程命名

为什么要命名

不同业务可能都会用到线程池,如果用jdk自身的线程池命名方式,在追溯问题的时候会带来很大麻烦,你将难以定位是哪块业务出的问题,因此给线程池中线程命名,显得非常重要,那么线程池应该如何命名呢?
我们从源码入手,了解一下创建定长线程池命名是在哪一步

    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
    }

从上面代码可以看到,参数中唯一能影响起名的就是创建的线程工厂,下面是有注释决定起名的部分

    static class DefaultThreadFactory implements ThreadFactory {
        // 这个是static的变量,所有线程池共用一个,第一个线程池的编号为1,第二个线程池编号为2,pool-1-thread-1里面的pool-1就是该值
        private static final AtomicInteger poolNumber = new AtomicInteger(1);
        private final ThreadGroup group;
        //线程级别线程编号,pool-1-thread-1里面的thread-1就是该值
        private final AtomicInteger threadNumber = new AtomicInteger(1);
        //线程池中线程的前缀,默认固定为pool
        private final String namePrefix;

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

        public Thread newThread(Runnable r) {
            //pool-1-thread-1
            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;
        }
    }

因此,我们可以推理出来,我们要自定义线程池中线程的名称很简单,我们可以自定义线程工厂实现基本的线程工厂接口,然后在下面创建线程池的时候调用带工厂的方法传入自己创建的工厂即可

    public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>(),
                                      threadFactory);
    }

当然实际应用的时候,我们自己写这个很多余,谷歌的guava包中已经给我们提供了自定义的实现

Executors.newFixedThreadPool(3,new ThreadFactoryBuilder().setNameFormat("任务线程:%d").build())
@CheckReturnValue
public ThreadFactory build() {
  return doBuild(this);
}
private static ThreadFactory doBuild(ThreadFactoryBuilder builder) {
    final String nameFormat = builder.nameFormat;
    final Boolean daemon = builder.daemon;
    final Integer priority = builder.priority;
    final UncaughtExceptionHandler uncaughtExceptionHandler = builder.uncaughtExceptionHandler;
    final ThreadFactory backingThreadFactory =
        (builder.backingThreadFactory != null)
            ? builder.backingThreadFactory
            : Executors.defaultThreadFactory();
    //从0开始
    final AtomicLong count = (nameFormat != null) ? new AtomicLong(0) : null;
    return new ThreadFactory() {
      @Override
      public Thread newThread(Runnable runnable) {
        Thread thread = backingThreadFactory.newThread(runnable);
        if (nameFormat != null) {
          thread.setName(format(nameFormat, count.getAndIncrement()));
        }
        if (daemon != null) {
          thread.setDaemon(daemon);
        }
        if (priority != null) {
          thread.setPriority(priority);
        }
        if (uncaughtExceptionHandler != null) {
          thread.setUncaughtExceptionHandler(uncaughtExceptionHandler);
        }
        return thread;
      }
    };
  }

通过上面的步骤我们即可创建一个线程数量为3的定长线程池,池中的线程序号从0开始

上一篇 下一篇

猜你喜欢

热点阅读