自定义 ExecutorService 中线程的名称

1、概览

ExecutorService 在 Java 中提供了一种方便的方式来管理线程并执行并发任务。在使用 ExecutorService 时,为线程和线程池分配有意义的名称可以提高调试、监控和理解线程的效果。

本文将带你了解在 Java 的 ExecutorService 中为线程和线程池命名的不同方式。

2、设置线程的名称

如果不使用 ExecutorService,可以在 Java 中通过 Thread#setName 方法轻松设置线程名。

ExecutorService 使用默认的线程池和线程名称,如 pool-1-thread-1pool-1-thread-2 等,但也可以为 ExecutorService 管理的线程指定自定义的线程名称。

首先,创建一个简单程序,执行 ExecuterService,输出默认的线程和线程池名称:

ExecutorService executorService = Executors.newFixedThreadPool(3);
for (int i = 0; i < 5; i++) {
    executorService.execute(() -> System.out.println(Thread.currentThread().getName()));
}

运行程序,输出如下:

pool-1-thread-1
pool-1-thread-2
pool-1-thread-1
pool-1-thread-3
pool-1-thread-2

2.1、使用自定义 ThreadFactory

ExecutorService 中,新线程是通过 ThreadFactory 创建的。ExecutorService 默认使用 Executors.defaultThreadFactory 创建线程来执行任务。

通过向 ExecuterService 提供不同的自定义 ThreadFactory,我们可以更改线程的名称、优先级等。

首先,创建 ThreadFactory 的实现:MyThreadFactory。然后,为 MyThreadFactory 创建的新线程设置自定义线程名称:

public class MyThreadFactory implements ThreadFactory {
    private AtomicInteger threadNumber = new AtomicInteger(1);
    private String threadlNamePrefix = "";

    public MyThreadFactory(String threadlNamePrefix) {
        this.threadlNamePrefix = threadlNamePrefix;
    }

    public Thread newThread(Runnable runnable) {
        // 创建线程,设置自定义名称
        return new Thread(runnable, threadlNamePrefix + threadNumber.getAndIncrement());
    }
}

然后,其传递给 ExecutorService

MyThreadFactory myThreadFactory = new MyThreadFactory("MyCustomThread-");
ExecutorService executorService = Executors.newFixedThreadPool(3, myThreadFactory);
for (int i = 0; i < 5; i++) {
    executorService.execute(() -> System.out.println(Thread.currentThread().getName()));
}

最后,执行程序,可以看到 ExecutorService 的线程打印出我们自定义的线程名称:

MyCustomThread-1
MyCustomThread-2
MyCustomThread-2
MyCustomThread-3
MyCustomThread-1

2.2、使用 Apache Commons 的 BasicThreadFactory

首先,将 commons-lang3 的依赖添加到项目中:

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.14.0</version>
</dependency>

然后,用自定义线程名称创建 BasicThreadFactory。最后,用自定义线程工厂创建 ExecutorService

BasicThreadFactory factory = new BasicThreadFactory.Builder()
  .namingPattern("MyCustomThread-%d").priority(Thread.MAX_PRIORITY).build();
ExecutorService executorService = Executors.newFixedThreadPool(3, factory);
for (int i = 0; i < 5; i++) {
    executorService.execute(() -> System.out.println(Thread.currentThread().getName()));
}

如上,通过 namingPattern() 方法设置了线程名称的命名模式。

最后,运行程序,打印出的自定义线程名称如下:

MyCustomThread-1
MyCustomThread-2
MyCustomThread-2
MyCustomThread-3
MyCustomThread-1

2.3、使用 Guava 的 ThreadFactoryBuilder

Guava 的 ThreadFactoryBuilder 也提供了创建自定义线程的选项。

首先,添加 guava 依赖:

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>33.2.0-jre</version>
</dependency>

然后,用自定义名称创建 ThreadFactory,并将其传递给 ExecutorService

ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
  .setNameFormat("MyCustomThread-%d").build();
ExecutorService executorService = Executors.newFixedThreadPool(3, namedThreadFactory);
for (int i = 0; i < 5; i++) {
    executorService.execute(() -> System.out.println(Thread.currentThread().getName()));
}

如上,通过 setNameFormat() 方法设置了线程名称的名称模式。

最后,运行程序,打印出的自定义线程名称如下:

MyCustomThread-0
MyCustomThread-1
MyCustomThread-2
MyCustomThread-2
MyCustomThread-1

以上是在使用 Java 中的 ExecutorService 时可以命名线程的一些方法,这些方法可以根据应用的需求灵活地选择。

3、总结

本文介绍了给 Java ExecutorService 中线程和线程池设置自定义名称的不同方法。

首先介绍了默认的线程名称,然后介绍了如何使用自定义 ThreadFactory 以及 Apache Commons 和 Guava 等不同 API 的 ThreadFactory 实现来自定义线程的名称。


Ref:https://www.baeldung.com/java-naming-executor-service-thread