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

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

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

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


当前回答

正如其他答案已经说过的,您可以创建并使用自己的java.util.concurrent.ThreadFactory接口的实现(不需要外部库)。 我把我的代码粘贴在下面,因为它不同于以前的答案,因为它使用字符串。Format方法,并将线程的基名称作为构造函数参数:

import java.util.concurrent.ThreadFactory;

public class NameableThreadFactory implements ThreadFactory{
    private int threadsNum;
    private final String namePattern;

    public NameableThreadFactory(String baseName){
        namePattern = baseName + "-%d";
    }

    @Override
    public Thread newThread(Runnable runnable){
        threadsNum++;
        return new Thread(runnable, String.format(namePattern, threadsNum));
    }    
}

这是一个用法的例子:

ThreadFactory  threadFactory = new NameableThreadFactory("listenerThread");        
final ExecutorService executorService = Executors.newFixedThreadPool(5, threadFactory);

编辑:使我的ThreadFactory实现线程安全,感谢@mchernyakov指出这一点。 尽管在ThreadFactory文档中没有任何地方说它的实现必须是线程安全的,但DefaultThreadFactory是线程安全的事实是一个很大的提示:

import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;

public class NameableThreadFactory implements ThreadFactory{
    private final AtomicInteger threadsNum = new AtomicInteger();

    private final String namePattern;

    public NameableThreadFactory(String baseName){
        namePattern = baseName + "-%d";
    }

    @Override
    public Thread newThread(Runnable runnable){
        return new Thread(runnable, String.format(namePattern, threadsNum.addAndGet(1)));
    }    
}

其他回答

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

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

Executors.newSingleThreadExecutor(new YourThreadFactory()).submit(someRunnable);

或者用Kotlin

Executors.newSingleThreadExecutor { r -> Thread(r, "Your name") }

如果使用Spring,可以为CustomizableThreadFactory设置线程名前缀。

例子:

ExecutorService alphaExecutor =
    Executors.newFixedThreadPool(10, new CustomizableThreadFactory("alpha-"));

或者,您可以使用ThreadPoolExecutorFactoryBean将ExecutorService创建为Spring bean——然后所有线程都将以beanName-前缀命名。

@Bean
public ThreadPoolExecutorFactoryBean myExecutor() {
    ThreadPoolExecutorFactoryBean executorFactoryBean = new ThreadPoolExecutorFactoryBean();
    // configuration of your choice
    return executorFactoryBean;
}

在上面的例子中,线程将以myExecutor-前缀命名。您可以显式地将前缀设置为不同的值(例如。通过在工厂bean上设置executorFactoryBean.setThreadNamePrefix("myPool-")来实现。

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

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

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

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-”方面的方法。或者像其他答案一样,使用一个单独的带有构造函数的类。

private class TaskThreadFactory implements ThreadFactory
{

    @Override
    public Thread newThread(Runnable r) {
        Thread t = new Thread(r, "TASK_EXECUTION_THREAD");

        return t;
    }

}

将ThreadFactory传递给一个executorservice,就可以开始了