假设我有一个利用Executor框架的应用程序
Executors.newSingleThreadExecutor().submit(new Runnable(){
@Override
public void run(){
// do stuff
}
}
当我在调试器中运行此应用程序时,将创建一个具有以下(默认)名称的线程:thread [pool-1-thread-1]。正如您所看到的,这并不是非常有用,而且据我所知,Executor框架并没有提供一种简单的方法来命名创建的线程或线程池。
那么,如何为线程/线程池提供名称呢?例如,Thread[fopool - foothread]。
您可以编写自己的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")
);
你可以提供一个ThreadFactory给newSingleThreadScheduledExecutor(ThreadFactory)。工厂将负责创建线程,并能够为它们命名。
引用Javadoc的话:
Creating new threads
New threads are created using a ThreadFactory. If not otherwise specified, a Executors.defaultThreadFactory() is used, that creates threads to all be in the same ThreadGroup and with the same NORM_PRIORITY priority and non-daemon status. By supplying a different ThreadFactory, you can alter the thread's name, thread group, priority, daemon status, etc. If a ThreadFactory fails to create a thread when asked by returning null from newThread, the executor will continue, but might not be able to execute any tasks
Oracle对此有一个开放的RFE。从甲骨文员工的评论来看,他们似乎不理解这个问题,也不会解决。在JDK中支持它是非常简单的事情之一(不会破坏向后兼容性),所以RFE被误解有点遗憾。
如前所述,您需要实现自己的ThreadFactory。如果您不想为了这个目的而引入Guava或Apache Commons,我在这里提供一个ThreadFactory实现供您使用。除了能够将线程名前缀设置为“pool”之外,它与您从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这一事实。
This
Executors.newSingleThreadExecutor();
将给出一个ExecutorService,其中线程命名为pool-N-thread-M,但使用
Executors.newSingleThreadExecutor(new ThreadFactoryWithNamePrefix("primecalc"));
您将得到一个ExecutorService,其中线程名为primecalc-N-thread-M。瞧!