假设我有一个利用Executor框架的应用程序

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

当我在调试器中运行此应用程序时,将创建一个具有以下(默认)名称的线程:thread [pool-1-thread-1]。正如您所看到的,这并不是非常有用,而且据我所知,Executor框架并没有提供一种简单的方法来命名创建的线程或线程池。

那么,如何为线程/线程池提供名称呢?例如,Thread[fopool - foothread]。


当前回答

这是我的定制工厂,为线程转储分析器提供定制名称。通常我只是给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") );

为了方便起见,这是一个用于调试的线程转储循环。

    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()
            );
        }
    }

其他回答

你也可以在线程执行之后更改线程的名称:

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

例如,如果您在不同类型的任务中使用相同的ThreadFactory,这可能会很有趣。

我想我要抛出一些简单的例子,只是为了让选项都在那里:

唯一的数字(也可以把它放到一个方法中):

AtomicInteger threadNum = new AtomicInteger(0);
ExecutorService e = Executors.newSingleThreadExecutor(r -> new Thread(r, "my-name-" + threadNum.incrementAndGet()));

唯一的编号和“可能”唯一的名称(如果您正在生成新的Runnable对象)。如果启动线程是在一个被多次调用的方法中,例如:

AtomicInteger threadNum = new AtomicInteger(0);
ExecutorService e = Executors.newSingleThreadExecutor(r -> new Thread(r, "my-name-" + threadNum.incrementAndGet() + "-" + r.hashCode()));

如果你真的想每次都有一个唯一的名字,你就需要一个带有静态变量的类(也可以在那里添加一个静态池号前缀,参见其他答案)。

在JDK < 8中等价(你不需要一个新的类,或者可以从一个方法中返回一个ThreadFactory):

Executors.newSingleThreadExecutor(new ThreadFactory() {
      AtomicInteger threadCount = new AtomicInteger(0);

      @Override
      public Thread newThread(Runnable r) {
        return new Thread(r, "your-name-" + threadCount.getAndIncrement() + "-" + r.hashCode()); // could also use Integer.toHexString(r.hashCode()) for shorter
      }
    }));

并且可以将其作为变量,作为“you-name-”方面的方法。或者像其他答案一样,使用一个单独的带有构造函数的类。

番石榴几乎总有你需要的东西。

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

并将它传递给您的ExecutorService。

Executors.newSingleThreadExecutor(r -> new Thread(r, "someName")).submit(getJob());

Runnable getJob() {
        return () -> {
            // your job
        };
}

ThreadFactory扩展

公共接口

根据需要创建新线程的对象。使用线程工厂消除了对新线程的硬连接,使应用程序能够使用特殊的线程子类、优先级等。

线程newThread(可运行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