假设我有一个使用Executor
框架的应用程序
Executors.newSingleThreadExecutor().submit(new Runnable(){
@Override
public void run(){
// do stuff
}
}
当我在调试器中运行此应用程序时,将使用以下(默认)名称创建一个线程:Thread[pool-1-thread-1]
。正如您所看到的,这并不是非常有用,据我所知,Executor
框架不能提供一种简单的方法来命名创建的线程或线程池。
那么,如何为线程/线程池提供名称呢?例如,Thread[FooPool-FooThread]
。
答案 0 :(得分:249)
番石榴几乎总是拥有你need的东西。
ThreadFactory namedThreadFactory =
new ThreadFactoryBuilder().setNameFormat("my-sad-thread-%d").build()
并将其传递给您的ExecutorService
。
答案 1 :(得分:103)
您可以向ThreadFactory
提供newSingleThreadScheduledExecutor(ThreadFactory threadFactory)
。工厂将负责创建线程,并且能够命名它们。
引用Javadoc:
创建新主题
使用
ThreadFactory
创建新主题。如果没有另外指定,则使用Executors.defaultThreadFactory()
,它创建的线程都在同一ThreadGroup
并具有相同的NORM_PRIORITY
优先级和非守护进程状态。通过提供不同的ThreadFactory
,您可以更改线程的名称,线程组,优先级,守护程序状态等。如果ThreadFactory
通过从newThread
返回null而无法创建线程,执行者将继续,但可能无法执行任何任务
答案 2 :(得分:86)
您可以尝试提供自己的线程工厂,它将创建具有适当名称的线程。这是一个例子:
class YourThreadFactory implements ThreadFactory {
public Thread newThread(Runnable r) {
return new Thread(r, "Your name");
}
}
Executors.newSingleThreadExecutor(new YourThreadFactory()).submit(someRunnable);
答案 3 :(得分:48)
您还可以在执行线程时更改线程的名称:
Thread.currentThread().setName("FooName");
如果你使用相同的ThreadFactory来处理不同类型的任务,那么这可能是有意义的。
答案 4 :(得分:43)
来自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);
答案 5 :(得分:19)
Oracle有一个open RFE。根据Oracle员工的评论,他们似乎不了解这个问题,也无法修复。这是JDK中支持简单易用的东西之一(没有破坏向后兼容性)所以RFE被误解是一种耻辱。
正如所指出的,你需要实现自己的ThreadFactory。如果您不想仅仅为了这个目的而引入Guava或Apache Commons,我在这里提供了一个ThreadFactory
实现,您可以使用它。它与您从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"));
您将获得一个名为primecalc-N-thread-M
的线程的ExecutorService。瞧!
答案 6 :(得分:14)
如果您使用的是Spring,则可以CustomizableThreadFactory
为其设置线程名称前缀。
示例:
ExecutorService alphaExecutor =
Executors.newFixedThreadPool(10, new CustomizableThreadFactory("alpha-"));
答案 7 :(得分:8)
private class TaskThreadFactory implements ThreadFactory
{
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r, "TASK_EXECUTION_THREAD");
return t;
}
}
将ThreadFactory传递给executorservice,你很高兴
答案 8 :(得分:6)
快速而肮脏的方法是在Thread.currentThread().setName(myName);
方法中使用run()
。
答案 9 :(得分:6)
<强> public interface ThreadFactory
强>
按需创建新线程的对象。使用线程工厂可以消除对新线程的调用的硬连线,使应用程序能够使用特殊的线程子类,优先级等。
<强> Thread newThread(Runnable r)
强>
构造一个新线程。实现还可以初始化优先级,名称,守护程序状态,ThreadGroup等。
示例代码:
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
....等
答案 10 :(得分:3)
$objPHPExcel->getActiveSheet()->setCellValueExplicit("$row17", $data->telephone,PHPExcel_Cell_DataType::TYPE_STRING);
答案 11 :(得分:3)
您可以编写自己的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")
);
答案 12 :(得分:2)
这是我的定制工厂,为线程转储分析器提供自定义名称。通常我只是给tf=null
重用JVM默认线程工厂。 This website has more advanced thread factory.
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()
);
}
}
答案 13 :(得分:2)
我以前经常做类似下面的事情(需要guava
库):
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("SO-POOL-%d").build();
ExecutorService executorService = Executors.newFixedThreadPool(5,namedThreadFactory);
答案 14 :(得分:1)
我用来装饰现有工厂的本地Java核心解决方案:
public class ThreadFactoryNameDecorator implements ThreadFactory {
private final ThreadFactory defaultThreadFactory;
private final String suffix;
public ThreadFactoryNameDecorator(String suffix) {
this(Executors.defaultThreadFactory(), suffix);
}
public ThreadFactoryNameDecorator(ThreadFactory threadFactory, String suffix) {
this.defaultThreadFactory = threadFactory;
this.suffix = suffix;
}
@Override
public Thread newThread(Runnable task) {
Thread thread = defaultThreadFactory.newThread(task);
thread.setName(thread.getName() + "-" + suffix);
return thread;
}
}
实际情况:
Executors.newSingleThreadExecutor(new ThreadFactoryNameDecorator("foo"));
答案 15 :(得分:1)
如果您只想更改单个线程执行器的名称,我发现将lambda用作线程工厂是最简单的。
Executors.newSingleThreadExecutor(runnable -> new Thread(runnable, "Your name"));
答案 16 :(得分:1)
就像已经回答的其他答案一样,您可以创建并使用自己的java.util.concurrent.ThreadFactory接口实现(不需要外部库)。 我在下面粘贴我的代码,因为它与以前的答案不同,因为它使用String.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);
答案 17 :(得分:1)
基于上面的一些评论,不同之处在于我只是使用了lambda
submittedPerson
答案 18 :(得分:1)
使用 Executors.defaultThreadFactory() 的现有功能但只设置名称:
<form className='form' onSubmit={handleSubmit}>
答案 19 :(得分:1)
我想我会给出一些简化的例子,这样选项就全在那里了:
唯一编号(也可以将其放入方法中):
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-”方面作为变量的方法。或者像其他答案一样使用带有构造函数的单独类。