Naming threads and thread-pools of ExecutorService
Asked Answered
O

21

296

Let's say I have an application that utilizes the Executor framework as such

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

When I run this application in the debugger, a thread is created with the following (default) name: Thread[pool-1-thread-1]. As you can see, this isn't terribly useful and as far as I can tell, the Executor framework does not provide an easy way to name the created threads or thread-pools.

So, how does one go about providing names for the threads/thread-pools? For instance, Thread[FooPool-FooThread].

Overmatch answered 24/5, 2011 at 16:33 Comment(0)
I
141

You could supply a ThreadFactory to newSingleThreadScheduledExecutor(ThreadFactory threadFactory). The factory will be responsibe for creating threads, and will be able to name them.

To quote the 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

Inrush answered 24/5, 2011 at 16:38 Comment(0)
S
339

Guava almost always has what you need.

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

and pass it off to your ExecutorService.

Subterfuge answered 17/3, 2012 at 9:6 Comment(4)
I'm not sure where to find "guava". There are a lot of parts to Google's Guava and there are dozens of libraries with the same name. I assume you mean search.maven.org/artifact/com.google.guava/guava/29.0-jre/…. Is that right? The link you provide suggests it is from Google, but Google also has about half a dozen artifacts on Maven/Sonatype named "guava".Dirichlet
@Dirichlet - If you are writing a non trivial Java project, you most likely should already have guava as a dependency. And here it is: github.com/google/guavaSubterfuge
@pathikrit, thanks! I think I need to study up on Guava more :-)Dirichlet
If you aren't using Guava, Apache Commons Lang also has BasicThreadFactory which is very similar.Microlith
I
141

You could supply a ThreadFactory to newSingleThreadScheduledExecutor(ThreadFactory threadFactory). The factory will be responsibe for creating threads, and will be able to name them.

To quote the 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

Inrush answered 24/5, 2011 at 16:38 Comment(0)
B
124

You can try to provide your own thread factory, which will create thread with appropriate names. Here's one example:

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

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

Or in Kotlin

Executors.newSingleThreadExecutor { r -> Thread(r, "Your name") }
Bathy answered 24/5, 2011 at 16:38 Comment(0)
L
78

You can also change the name of your thread afterwards, while the thread is executed:

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

That could be of interest if for instance you're using the same ThreadFactory for different type of tasks.

Lamination answered 31/10, 2013 at 10:5 Comment(4)
This worked nicely because as FlorianT described, I have many different types of threads and didn't want to have to create multiple ThreadFactory objects just for the name. I called Thread.currentThread().setName("FooName"); as the first line in each run() method.Wreckful
One minor issue with this is when the failure behavior described in the docs occurs: (Note however that if this single thread terminates due to a failure during execution prior to shutdown, a new one will take its place if needed to execute subsequent tasks.). If the ExecutorService replaces the thread, it will be named by the ThreadFactory. Then again, seeing the name disappear while debugging could be a useful indicator.Cymene
As the other answer says, this is a quick and dirty method to set the name, and if you do so with multiple threads, all will be have the same name!!Klepht
Might want to set the thread name back to original upon exit, because it may retain the name even if it is working on different unrelated tasks.Matterhorn
V
61

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:

 // 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);
Vinylidene answered 25/5, 2011 at 14:45 Comment(0)
H
53

If you are using Spring, there is CustomizableThreadFactory for which you can set a thread name prefix.

Example:

ExecutorService alphaExecutor =
    Executors.newFixedThreadPool(10, new CustomizableThreadFactory("alpha-"));

Alternatively, you can create your ExecutorService as a Spring bean using ThreadPoolExecutorFactoryBean - then the threads will all be named with the beanName- prefix.

@Bean
public ThreadPoolExecutorFactoryBean myExecutor() {
    ThreadPoolExecutorFactoryBean executorFactoryBean = new ThreadPoolExecutorFactoryBean();
    // configuration of your choice
    return executorFactoryBean;
}

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 setting executorFactoryBean.setThreadNamePrefix("myPool-") on the factory bean.

Hat answered 7/1, 2016 at 8:13 Comment(2)
can't find CustomizableThreadFactory? i am using jdk 1.7. any idea what am i missing here?Brawley
@KamranShahid this is a Spring Framework class, you must use Spring to have itHat
O
30

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".

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;
    }
}

When you want to use it you simply take advantage of the fact that all Executors methods allow you to provide your own ThreadFactory.

This

    Executors.newSingleThreadExecutor();

will give an ExecutorService where threads are named pool-N-thread-M but by using

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

you'll get an ExecutorService where threads are named primecalc-N-thread-M. Voila!

Obrian answered 16/5, 2015 at 18:52 Comment(4)
You have missed a closing parenthesis in your last snippetGastrology
Just a quick note that SonarLint/Qube prefers to not use ThreadGroup in favor of ThreadPoolExecutor.Arnitaarno
Exactly, SonarLint compliant with the code but if you change the class it doesn't compile anymore.Rinarinaldi
Very nice, it retains the pool number/thread number :)Ocher
C
13

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:

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

And this is an example of usage:

ThreadFactory  threadFactory = new NameableThreadFactory("listenerThread");        
final ExecutorService executorService = Executors.newFixedThreadPool(5, threadFactory);

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 the DefaultThreadFactory is thread-safe is a big hint:

import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;

public class NameableThreadFactory implements ThreadFactory{
    private final AtomicInteger threadsNum = new AtomicInteger();

    private final String namePattern;

    public NameableThreadFactory(String baseName){
        namePattern = baseName + "-%d";
    }

    @Override
    public Thread newThread(Runnable runnable){
        return new Thread(runnable, String.format(namePattern, threadsNum.addAndGet(1)));
    }    
}
Chloramphenicol answered 25/5, 2019 at 11:34 Comment(2)
You thread counter (threadsNum) is not threadsafe, you should use AtomicInteger.Winson
Thanks for pointing it out, @Winson I have just edited my answer accordingly.Echt
L
11

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.

Executors.newSingleThreadExecutor(runnable -> new Thread(runnable, "Your name"));
Lilith answered 28/1, 2019 at 10:49 Comment(4)
this creates two threads. One named "Your name" and another "pool-N-thread-M"Ria
@Ria No, it doesn't. Taking a thread dump from a minimal example which uses the executor to run a thread which sleeps shows the following threads: main@1, Finalizer@667, Reference Handler@668, Your name@665, Signal Dispatcher@666Lilith
Hum, it did when I tried it. It makes sense that it would since if you pass it a new Runnable() it creates a thread for you, and you are creating a thread yourself.Ria
I expect that you used a ThreadPoolExecutor instead or had one running for some other purpose. This code will not create a "pool-N-thread-M" thread. Also, I don't believe that it does make sense that it would. Your statement "if you pass it a new Runnable() it creates a thread for you" is not correct. It uses that runnable to create a thread and does that once because it's a single-thread executor. Only 1 thread is created.Lilith
X
9

A quick and dirty way is to use Thread.currentThread().setName(myName); in the run() method.

Xylina answered 18/7, 2014 at 7:46 Comment(1)
Duplicate of FlorianT's answer?Ocher
S
8
private class TaskThreadFactory implements ThreadFactory
{

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

        return t;
    }

}

Pass the ThreadFactory to an executorservice and you are good to go

Sewerage answered 8/1, 2014 at 18:16 Comment(0)
P
8

Extend ThreadFactory

public interface ThreadFactory

An object that creates new threads on demand. Using thread factories removes hardwiring of calls to new Thread, enabling applications to use special thread subclasses, priorities, etc.

Thread newThread(Runnable r)

Constructs a new Thread. Implementations may also initialize priority, name, daemon status, ThreadGroup, etc.

Sample code:

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

output:

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

....etc

Presentative answered 5/2, 2016 at 15:59 Comment(2)
You thread counter is not thread-safe: you should use an AtomicInteger.Musgrove
Thanks for suggestion. I have incorporated your suggestion.Presentative
H
7

Based on few of the comments above, difference is I just used lambda

Executors.newFixedThreadPool(10, r -> new Thread(r, "my-threads-%d"))
Hughs answered 20/11, 2020 at 7:27 Comment(1)
What's the %d for? Is this supposed to be like NameableThreadFactory from the other answer?Ocher
P
6

Using the existing functionality of Executors.defaultThreadFactory() but just setting the name:

import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;

public class NamingThreadFactory implements ThreadFactory {
    private final String prefix;
    private final AtomicInteger threadNumber = new AtomicInteger(0);

    public NamingThreadFactory(String prefix){
        this.prefix = prefix;
    }

    @Override
    public Thread newThread(Runnable r) {
        Thread t = Executors.defaultThreadFactory().newThread(r);
        t.setName(prefix + threadNumber.addAndGet(1));
        return t;
    }
}
Pirn answered 13/1, 2021 at 9:43 Comment(3)
The only change I would make would be to create the Executors.defaultThreadFactory() in the class constructor. I don't see why it would be needed to recreate the factory on every new Thread creation.Gastrology
@Gastrology not sure if Executors.defaultThreadFactory() creates a new factory. Are you sure that's the case?Pirn
public static ThreadFactory defaultThreadFactory() { return new DefaultThreadFactory(); }Gastrology
I
5

I use to do same like below (requires guava library) :

ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("SO-POOL-%d").build();
ExecutorService executorService = Executors.newFixedThreadPool(5,namedThreadFactory);
Imprecision answered 7/8, 2018 at 9:45 Comment(1)
Worth noting that ThreadFactoryBuilder is from the Google Guava library.Haehaecceity
J
5

The home-grown core Java solution that I use to decorate existing factories:

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;
    }
}

In action:

Executors.newSingleThreadExecutor(new ThreadFactoryNameDecorator("foo"));
Jitterbug answered 25/1, 2019 at 7:3 Comment(2)
Why the extra constructor?Ocher
If you want to decorate an existing ThreadFactory instance. If you don't need it, just remove itJitterbug
S
4
Executors.newSingleThreadExecutor(r -> new Thread(r, "someName")).submit(getJob());

Runnable getJob() {
        return () -> {
            // your job
        };
}
Steviestevy answered 3/12, 2016 at 23:25 Comment(0)
R
3

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:

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;
    }
}

And usage:

Executors.newSingleThreadExecutor(new ThreadFactoryWithCustomName(
        Executors.defaultThreadFactory(),
        "customName")
    );
Respecting answered 6/2, 2017 at 10:25 Comment(0)
M
3

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.

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

For your convenience this is a thread dump loop for debug purpose.

    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()
            );
        }
    }
Marlin answered 25/8, 2017 at 10:39 Comment(1)
This worked really well for me, somewhat surprised it wasnt upvoted much. Either way cheers.Deaden
O
1

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):

AtomicInteger threadNum = new AtomicInteger(0);
ExecutorService e = Executors.newSingleThreadExecutor(r -> new Thread(r, "my-name-" + threadNum.incrementAndGet()));

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:

AtomicInteger threadNum = new AtomicInteger(0);
ExecutorService e = Executors.newSingleThreadExecutor(r -> new Thread(r, "my-name-" + threadNum.incrementAndGet() + "-" + r.hashCode()));

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):

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

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.

Ocher answered 13/1, 2021 at 18:14 Comment(0)
T
1

Since Java 21

Executors.newSingleThreadExecutor(Thread.ofPlatform().name("FooPool-FooThread-",1).factory());

or for a pool of 4 threads:

Executors.newFixedThreadPool(4,Thread.ofPlatform().name("FooPool-FooThread-",1).factory());
Toggle answered 16/2, 2024 at 18:30 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.