ExecutorService 的线程和线程池命名
假设我有一个使用 Executor 框架的应用程序,
Executors.newSingleThreadExecutor().submit(new Runnable(){
@Override
public void run(){
// do stuff
}
}
当我在调试器中运行此应用程序时,会创建一个具有以下(默认)名称的线程:Thread[pool-1-线程1]。正如您所看到的,这并不是很有用,而且据我所知,Executor 框架没有提供一种简单的方法来命名创建的线程或线程池。
那么,如何为线程/线程池提供名称呢?例如,Thread[FooPool-FooThread]
。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(21)
Guava 几乎总有您想要的需要。
并将其传递给您的ExecutorService。
Guava almost always has what you need.
and pass it off to your
ExecutorService
.您可以提供
ThreadFactory
到newSingleThreadScheduledExecutor(ThreadFactory threadFactory)
。工厂将负责创建线程,并能够命名它们。引用 Javadoc:
You could supply a
ThreadFactory
tonewSingleThreadScheduledExecutor(ThreadFactory threadFactory)
. The factory will be responsibe for creating threads, and will be able to name them.To quote the Javadoc:
您可以尝试提供自己的线程工厂,它将创建具有适当名称的线程。这是一个例子:
或者在 Kotlin 中
You can try to provide your own thread factory, which will create thread with appropriate names. Here's one example:
Or in Kotlin
您还可以在执行线程时更改线程的名称:
例如,如果您对不同类型的任务使用相同的 ThreadFactory,这可能会很有趣。
You can also change the name of your thread afterwards, while the thread is executed:
That could be of interest if for instance you're using the same ThreadFactory for different type of tasks.
BasicThreadFactory
对于提供命名行为也很有用。您可以使用 Builder 根据需要命名线程,而不是编写匿名内部类。这是 javadoc 中的示例:The
BasicThreadFactory
from apache commons-lang is also useful to provide the naming behavior. Instead of writing an anonymous inner class, you can use the Builder to name the threads as you want. Here's the example from the javadocs:如果您使用 Spring,则有
CustomizedThreadFactory
,您可以为其设置线程名称前缀。示例:
或者,您可以使用
ThreadPoolExecutorFactoryBean
- 那么线程都将以beanName-
前缀命名。在上面的示例中,线程将以
myExecutor-
前缀命名。您可以通过在工厂 bean 上设置executorFactoryBean.setThreadNamePrefix("myPool-")
来将前缀显式设置为不同的值(例如"myPool-"
)。If you are using Spring, there is
CustomizableThreadFactory
for which you can set a thread name prefix.Example:
Alternatively, you can create your
ExecutorService
as a Spring bean usingThreadPoolExecutorFactoryBean
- then the threads will all be named with thebeanName-
prefix.In the example above, the threads will be named with
myExecutor-
prefix. You can set the prefix explicitly to a different value (eg."myPool-"
) by settingexecutorFactoryBean.setThreadNamePrefix("myPool-")
on the factory bean.Oracle 有一个开放 RFE。从 Oracle 员工的评论来看,他们似乎不理解这个问题,也不会解决。这是 JDK 中支持非常简单的事情之一(不会破坏向后兼容性),因此 RFE 被误解是一种耻辱。
正如所指出的,您需要实现自己的 ThreadFactory< /a>.如果您不想仅出于此目的引入 Guava 或 Apache Commons,我在这里提供了您可以使用的 ThreadFactory 实现。它与您从 JDK 获得的内容完全相同,除了能够将线程名称前缀设置为“pool”之外的其他内容。
当您想使用它时,您只需利用所有
Executors
方法都允许您提供自己的ThreadFactory
的事实。这
将提供一个 ExecutorService,其中线程名为
pool-N-thread-M
,但通过使用,您将获得一个 ExecutorService,其中线程名为
primecalc-N-thread-M
。瞧!There's an open RFE for this with Oracle. From the comments from the Oracle employee it seems they don't understand the issue and won't fix. It's one of these things that is dead simple to support in the JDK (without breaking backwards compatibility) so it is kind of a shame that the RFE gets misunderstood.
As pointed out you need to implement your own ThreadFactory. If you don't want to pull in Guava or Apache Commons just for this purpose I provide here a
ThreadFactory
implementation that you can use. It is exactly similar to what you get from the JDK except for the ability to set the thread name prefix to something else than "pool".When you want to use it you simply take advantage of the fact that all
Executors
methods allow you to provide your ownThreadFactory
.This
will give an ExecutorService where threads are named
pool-N-thread-M
but by usingyou'll get an ExecutorService where threads are named
primecalc-N-thread-M
. Voila!正如其他答案已经说过的,您可以创建并使用您自己的 java.util.concurrent.ThreadFactory 接口的实现(不需要外部库)。
我将代码粘贴在下面,因为它与以前的答案不同,因为它使用
String.format
方法并采用线程的基本名称作为构造函数参数:这是一个用法示例:
编辑:使我的
ThreadFactory
实现线程安全,感谢@mchernyakov指出这一点。尽管 ThreadFactory 文档中没有任何地方说它的实现必须是线程安全的,但 DefaultThreadFactory 是线程安全的事实是一个很大的暗示:
As other answers already said, you may create and use your own implementation of the
java.util.concurrent.ThreadFactory
interface (no external libraries required).I am pasting my code below because it is different than previous answers since it uses
String.format
method and takes a base name for the threads as a constructor argument:And this is an example of usage:
EDIT: making my
ThreadFactory
implementation thread-safe, thanks to @mchernyakov for pointing it out.Even though nowhere in the
ThreadFactory
documentation is said that its implementations must be thread-safe, the fact that theDefaultThreadFactory
is thread-safe is a big hint:我发现如果您只想更改单个线程执行器的名称,那么使用 lambda 作为线程工厂是最简单的。
I find it easiest to use a lambda as a thread factory if you just want to change the name for a single thread executor.
一种快速但肮脏的方法是在
run()
方法中使用Thread.currentThread().setName(myName);
。A quick and dirty way is to use
Thread.currentThread().setName(myName);
in therun()
method.将 ThreadFactory 传递给执行服务,然后就可以开始了
Pass the ThreadFactory to an executorservice and you are good to go
扩展 ThreadFactory
公共接口ThreadFactory
Thread newThread(Runnable r)
示例代码:
输出:
...等
Extend ThreadFactory
public interface ThreadFactory
Thread newThread(Runnable r)
Sample code:
output:
....etc
使用 执行器的现有功能。 defaultThreadFactory() 但只是设置名称:
Using the existing functionality of Executors.defaultThreadFactory() but just setting the name:
根据上面的一些评论,不同之处在于我只使用了 lambda
Based on few of the comments above, difference is I just used lambda
我经常这样做(需要
guava
库):I use to do same like below (requires
guava
library) :我用来装饰现有工厂的本土核心 Java 解决方案:
实际应用:
The home-grown core Java solution that I use to decorate existing factories:
In action:
您可以编写自己的 ThreadFactory 实现,例如使用一些现有的实现(如 defaultThreadFactory)并在最后更改名称。
实现 ThreadFactory 的示例:
及用法:
You can write your own implementation of ThreadFactory, using for example some existing implementation (like defaultThreadFactory) and change the name at the end.
Example of implementing ThreadFactory:
And usage:
这是我的定制工厂,为线程转储分析器提供定制名称。通常我只是给出 tf=null 来重用 JVM 默认线程工厂。 该网站有更高级的线程工厂。
为了您的方便,这是一个用于调试目的的线程转储循环。
This is my customized factory providing a customized names for thread dump analyzers. Usually I just give
tf=null
to reuse JVM default thread factory. This website has more advanced thread factory.For your convenience this is a thread dump loop for debug purpose.
我想我会抛出一些简化的示例,这样选项就全部存在:
唯一编号(也可以将其放入方法中):
唯一编号和“可能”唯一名称(如果您正在生成新的 Runnable 对象)。如果在多次调用的方法中启动线程,则很有用,例如:
如果您每次需要一个具有静态变量的类时确实想要一个唯一的名称(并且还可以在也有,请参阅其他答案)。
以及 JDK 中的等效项 < 8(您不需要为其创建一个新类,或者可以从方法中返回 ThreadFactory):
并且可以将其作为变量作为“you-name-”方面的方法。或者像其他答案一样使用带有构造函数的单独类。
Thought I'd throw in some simplified examples, just so the options are all out there:
Unique number (could also put this into a method):
Unique number and "probably" unique name (if you're generating new Runnable objects). Useful if starting off the threads is within a method that gets called more than once, for instance:
If you really wanted a unique name each time you'd need a class with a static var (and could also add a static pool number prefix in there as well, see other answers).
and an equivalent in JDK < 8 (you don't need a new class for it, or could return a ThreadFactory out of a method):
And could make that into a method for the "you-name-" aspect as a variable. Or use a separate class with a constructor like the other answers all seem to.
从 Java 21 开始
或对于 4 个线程的池:
Since Java 21
or for a pool of 4 threads: