2011-05-24 124 views
147
的线程池

比方说,我有当我运行在调试这个应用程序,它利用Executor框架等命名线程和ExecutorService的

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

的应用,线程与以下(默认)创建名称:Thread[pool-1-thread-1]。正如你所看到的,这不是非常有用,并且据我所知,框架并没有提供简单的方法来命名创建的线程或线程池。

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

回答

80

你可以提供一个ThreadFactorynewSingleThreadScheduledExecutor(ThreadFactory threadFactory)。工厂将负责创建线程,并能够为其命名。

引述Javadoc

创建新主题

新线程使用的是ThreadFactory创建。如果未另外指定,则使用Executors.defaultThreadFactory(),该创建的线程将全部处于相同的ThreadGroup中,并且具有相同的NORM_PRIORITY优先级和非守护进程状态。通过提供不同的ThreadFactory,您可以更改线程的名称,线程组,优先级,守护进程状态等。如果ThreadFactory在被要求时从newThread返回null时未能创建线程,则执行程序将继续,但可能无法执行任何任务

63

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

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

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

来自apache commons-lang的BasicThreadFactory也可用于提供命名行为。您可以使用Builder来根据需要命名线程,而不是编写匿名内部类。下面是从的javadoc的例子:

// 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); 
198

番石榴几乎总是你有什么need

ThreadFactory namedThreadFactory = 
    new ThreadFactoryBuilder().setNameFormat("my-sad-thread-%d").build() 

并将其传递给您的ExecutorService

+0

太棒了! – 2016-10-14 07:48:31

37

你也可以改变你的线程的名称后,在执行线程:

Thread.currentThread().setName("FooName"); 

这可能是感兴趣举例来说如果您使用的是不同类型的任务相同的ThreadFactory。

+5

这很好,因为FlorianT描述,我有很多不同类型的线程,并不想为名称创建多个ThreadFactory对象。我称之为Thread.currentThread()。setName(“FooName”);作为每个run()方法的第一行。 – 2014-01-02 22:08:54

+5

这个问题的一个小问题是当文档中描述的失败行为发生时:'(但是请注意,如果这个单线程由于在关闭之前的执行期间的失败而终止,如果需要执行后续任务,则新的线程将取代它的位置)'。如果ExecutorService取代该线程,它将由ThreadFactory命名。然后,再次看到名称消失,而调试可能是一个有用的指标。 – sethro 2014-02-18 19:19:24

+0

简直太棒了!谢谢。 – asgs 2015-06-17 18:16:45

8
private class TaskThreadFactory implements ThreadFactory 
{ 

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

     return t; 
    } 

} 

传递的ThreadFactory到一个ExecutorService,你是好去

6

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

15

对于Oracle来说,有一个open RFE。从Oracle员工的评论看来,他们似乎不了解这个问题,也无法解决问题。这是其中一种在JDK中很容易支持的事情(没有破坏向后兼容性),因此RFE被误解是一种遗憾。

正如你指出的那样,你需要实现你自己的ThreadFactory。如果您不想为此目的而使用Guava或Apache Commons,我在这里提供您可以使用的ThreadFactory实现。它与您从JDK获得的内容完全相似,除了可以将线程名称前缀设置为“pool”之外的其他内容。

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(); 

会给地方线程使用

Executors.newSingleThreadExecutor(new ThreadFactoryWithNamePrefix("primecalc"); 

你会得到其中的线程被命名为primecalc-N-thread-M一个ExecutorService命名pool-N-thread-M而是由ExecutorService的。瞧!

5

扩展ThreadFactory

public interface ThreadFactory

根据需要创建新线程的对象。使用线程工厂删除调用新的Thread的硬连线,让应用程序能够使用特殊的线程子类,优先级等

Thread newThread(Runnable r)

构造一个新线程。实现也可能初始化的优先级,名称,守护进程状态,线程组等

示例代码:

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 

....等

+1

您的线程计数器不是线程安全的:您应该使用AtomicInteger。 – Pino 2016-11-03 11:45:32

+0

感谢您的建议。我已经纳入你的建议。 – 2016-11-03 12:04:56

2
Executors.newSingleThreadExecutor(r -> new Thread(r, "someName")).submit(getJob()); 

Runnable getJob() { 
     return() -> { 
      // your job 
     }; 
} 
2

你可以编写自己的ThreadFactory实现,使用for例如一些现有的实现(如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") 
    ); 
3

这是我定制的工厂提供线程转储分析器一个自定义名称。通常我只给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() 
      ); 
     } 
    } 
+0

这对我来说真的很好,有点惊讶它没有提高很多。无论哪种方式欢呼。 – codedcosmos 2018-01-24 06:03:45

相关问题