命名ExecutorService的线程和线程池

比方说,我有一个使用Executor框架的应用程序

 Executors.newSingleThreadExecutor().submit(new Runnable(){ @Override public void run(){ // do stuff } } 

当我在debugging器中运行这个应用程序时,将使用以下(默认)名称创build一个线程: Thread[pool-1-thread-1] 。 正如你所看到的,这不是非常有用的,据我所知, Executor框架不提供一个简单的方法来命名创build的线程或线程池。

那么,如何为线程/线程池提供名称呢? 比如Thread[FooPool-FooThread]

你可以提供一个ThreadFactorynewSingleThreadScheduledExecutor(ThreadFactory threadFactory) 。 工厂将负责创build线程,并能够命名它们。

引用Javadoc :

创build新线程

新线程是使用ThreadFactory创build的。 如果没有另外指定,则使用Executors.defaultThreadFactory() ,该线程创build线程,使其全部位于同一个ThreadGroup并具有相同的NORM_PRIORITY优先级和非守护进程状态。 通过提供不同的ThreadFactory ,您可以更改线程的名称,线程组,优先级,守护进程状态等。如果在从newThread返回null时,如果ThreadFactory无法创build线程,则执行程序将继续,但可能无法执行任何任务

番石榴几乎总是有你所需要的 。

 ThreadFactory namedThreadFactory = new ThreadFactoryBuilder() .setNameFormat("my-sad-thread-%d").build() 

并将其传递给您的ExecutorService

您可以尝试提供您自己的线程工厂,这将创build具有适当名称的线程。 这里有一个例子:

 class YourThreadFactory implements ThreadFactory { public Thread newThread(Runnable r) { return new Thread(r, "Your name"); } } Executors.newSingleThreadExecutor(new YourThreadFactory()).submit(someRunnable); 

来自apache commons-lang的BasicThreadFactory也可以提供命名行为。 而不是编写一个匿名的内部类,您可以使用Builder来根据需要命名线程。 下面是javadocs的例子:

  // Create a factory that produces daemon threads with a naming pattern and // a priority BasicThreadFactory factory = new BasicThreadFactory.Builder() .namingPattern("workerthread-%d") .daemon(true) .priority(Thread.MAX_PRIORITY) .build(); // Create an executor service for single-threaded execution ExecutorService exec = Executors.newSingleThreadExecutor(factory); 

之后你也可以在线程执行的时候改变线程的名字:

 Thread.currentThread().setName("FooName"); 

例如,如果你使用相同的ThreadFactory来执行不同types的任务,这可能是有意义的。

Oracle有一个开放的RFE 。 从甲骨文员工的意见看来,他们不理解这个问题,不会解决。 这是在JDK中简单支持的事情之一(没有破坏向后兼容性),所以RFE被误解是一种遗憾。

正如你指出的,你需要实现你自己的ThreadFactory 。 如果你不想为了这个目的而使用Guava或Apache Commons,那么我在这里提供一个你可以使用的ThreadFactory实现。 除了能够将线程名称前缀设置为“pool”之外的function之外,它与从JDK获得的内容完全相似。

 package org.demo.concurrency; import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicInteger; /** * ThreadFactory with the ability to set the thread name prefix. * This class is exactly similar to * {@link java.util.concurrent.Executors#defaultThreadFactory()} * from JDK8, except for the thread naming feature. * * <p> * The factory creates threads that have names on the form * <i>prefix-N-thread-M</i>, where <i>prefix</i> * is a string provided in the constructor, <i>N</i> is the sequence number of * this factory, and <i>M</i> is the sequence number of the thread created * by this factory. */ public class ThreadFactoryWithNamePrefix implements ThreadFactory { // Note: The source code for this class was based entirely on // Executors.DefaultThreadFactory class from the JDK8 source. // The only change made is the ability to configure the thread // name prefix. private static final AtomicInteger poolNumber = new AtomicInteger(1); private final ThreadGroup group; private final AtomicInteger threadNumber = new AtomicInteger(1); private final String namePrefix; /** * Creates a new ThreadFactory where threads are created with a name prefix * of <code>prefix</code>. * * @param prefix Thread name prefix. Never use a value of "pool" as in that * case you might as well have used * {@link java.util.concurrent.Executors#defaultThreadFactory()}. */ public ThreadFactoryWithNamePrefix(String prefix) { SecurityManager s = System.getSecurityManager(); group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup(); namePrefix = prefix + "-" + poolNumber.getAndIncrement() + "-thread-"; } @Override 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; } } 

当你想使用它时,你只需要利用所有Executors方法允许你提供你自己的ThreadFactory的事实。

这个

  Executors.newSingleThreadExecutor(); 

将给出一个ExecutorService,其中线程被命名为pool-N-thread-M但是通过使用

  Executors.newSingleThreadExecutor(new ThreadFactoryWithNamePrefix("primecalc"); 

你会得到一个ExecutorService,其中的线程被命名为primecalc-N-thread-M 。 瞧!

 private class TaskThreadFactory implements ThreadFactory { @Override public Thread newThread(Runnable r) { Thread t = new Thread(r, "TASK_EXECUTION_THREAD"); return t; } } 

将ThreadFactory传递给一个executorservice,你很好

如果您使用的是Spring,则有CustomizableThreadFactory ,您可以为其设置线程名称前缀。

一个快速和肮脏的方法是使用Thread.currentThread().setName(myName);run()方法中。

扩展ThreadFactory

public interface ThreadFactory

按需创build新线程的对象。 使用线程工厂可以删除对新线程的硬连线,使应用程序可以使用特殊的线程子类,优先级等。

Thread newThread(Runnable r)

构造一个新的线程。 实现还可以初始化优先级,名称,守护进程状态,线程组等。

示例代码:

 import java.util.concurrent.*; import java.util.concurrent.atomic.*; import java.util.concurrent.ThreadPoolExecutor.DiscardPolicy; class SimpleThreadFactory implements ThreadFactory { String name; AtomicInteger threadNo = new AtomicInteger(0); public SimpleThreadFactory (String name){ this.name = name; } public Thread newThread(Runnable r) { String threadName = name+":"+threadNo.incrementAndGet(); System.out.println("threadName:"+threadName); return new Thread(r,threadName ); } public static void main(String args[]){ SimpleThreadFactory factory = new SimpleThreadFactory("Factory Thread"); ThreadPoolExecutor executor= new ThreadPoolExecutor(1,1,60, TimeUnit.SECONDS,new ArrayBlockingQueue<Runnable>(1),new ThreadPoolExecutor.DiscardPolicy()); final ExecutorService executorService = Executors.newFixedThreadPool(5,factory); for ( int i=0; i < 100; i++){ executorService.submit(new Runnable(){ public void run(){ System.out.println("Thread Name in Runnable:"+Thread.currentThread().getName()); } }); } executorService.shutdown(); } } 

输出:

 java SimpleThreadFactory thread no:1 thread no:2 Thread Name in Runnable:Factory Thread:1 Thread Name in Runnable:Factory Thread:2 thread no:3 thread no:4 Thread Name in Runnable:Factory Thread:3 Thread Name in Runnable:Factory Thread:4 thread no:5 Thread Name in Runnable:Factory Thread:5 

….等等

 Executors.newSingleThreadExecutor(r -> new Thread(r, "someName")).submit(getJob()); Runnable getJob() { return () -> { // your job }; } 

你可以编写你自己的ThreadFactory的实现,例如使用一些现有的实现(比如defaultThreadFactory),最后改变名字。

实现ThreadFactory的例子:

 class ThreadFactoryWithCustomName implements ThreadFactory { private final ThreadFactory threadFactory; private final String name; public ThreadFactoryWithCustomName(final ThreadFactory threadFactory, final String name) { this.threadFactory = threadFactory; this.name = name; } @Override public Thread newThread(final Runnable r) { final Thread thread = threadFactory.newThread(r); thread.setName(name); return thread; } } 

和用法:

 Executors.newSingleThreadExecutor(new ThreadFactoryWithCustomName( Executors.defaultThreadFactory(), "customName") ); 

这是我的定制工厂为线程转储分析器提供了一个定制的名称。 通常我只是给tf=null重用JVM默认线程工厂。 这个网站有更高级的线程工厂。

 public class SimpleThreadFactory implements ThreadFactory { private ThreadFactory tf; private String nameSuffix; public SimpleThreadFactory (ThreadFactory tf, String nameSuffix) { this.tf = tf!=null ? tf : Executors.defaultThreadFactory(); this.nameSuffix = nameSuffix; } @Override public Thread newThread(Runnable task) { // default "pool-1-thread-1" to "pool-1-thread-1-myapp-MagicTask" Thread thread=tf.newThread(task); thread.setName(thread.getName()+"-"+nameSuffix); return thread; } } - - - - - ExecutorService es = Executors.newFixedThreadPool(4, new SimpleThreadFactory(null, "myapp-MagicTask") ); 

为了您的方便,这是一个用于debugging目的的线程转储循环。

  ThreadMXBean mxBean=ManagementFactory.getThreadMXBean(); long[] tids = mxBean.getAllThreadIds(); System.out.println("------------"); System.out.println("ThreadCount="+tids.length); for(long tid : tids) { ThreadInfo mxInfo=mxBean.getThreadInfo(tid); if (mxInfo==null) { System.out.printf("%d %s\n", tid, "Thread not found"); } else { System.out.printf("%d %s, state=%s, suspended=%d, lockowner=%d %s\n" , mxInfo.getThreadId(), mxInfo.getThreadName() , mxInfo.getThreadState().toString() , mxInfo.isSuspended()?1:0 , mxInfo.getLockOwnerId(), mxInfo.getLockOwnerName() ); } }