Именование потоков и пулов потоков ExecutorService - PullRequest
195 голосов
/ 24 мая 2011

Допустим, у меня есть приложение, которое использует фреймворк Executor как таковой

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

Когда я запускаю это приложение в отладчике, создается поток со следующим (по умолчанию) именем: Thread[pool-1-thread-1]. Как видите, это не очень полезно, и, насколько я могу судить, инфраструктура Executor не предоставляет простой способ именования созданных потоков или пулов потоков.

Итак, как можно обеспечить имена для потоков / пулов потоков? Например, Thread[FooPool-FooThread].

Ответы [ 17 ]

3 голосов
/ 06 февраля 2017

Вы можете написать собственную реализацию 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")
    );
3 голосов
/ 04 декабря 2016
Executors.newSingleThreadExecutor(r -> new Thread(r, "someName")).submit(getJob());

Runnable getJob() {
        return () -> {
            // your job
        };
}
2 голосов
/ 07 августа 2018

Я использую, чтобы сделать то же самое, как показано ниже (требуется guava библиотека):

ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("SO-POOL-%d").build();
ExecutorService executorService = Executors.newFixedThreadPool(5,namedThreadFactory);
2 голосов
/ 25 августа 2017

Это моя настроенная фабрика, предоставляющая настроенные имена для анализаторов дампа потока. Обычно я просто даю tf=null для повторного использования фабрики потоков JVM по умолчанию. Этот сайт имеет более продвинутую фабрику ниток.

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()
            );
        }
    }
1 голос
/ 25 мая 2019

Как уже говорилось в других ответах, вы можете создать и использовать собственную реализацию интерфейса 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);
1 голос
/ 28 января 2019

Я считаю, что проще всего использовать лямбду в качестве фабрики потоков, если вы просто хотите изменить имя для одного исполнителя потока.

Executors.newSingleThreadExecutor(runnable -> new Thread(runnable, "Your name"));
1 голос
/ 25 января 2019

Самодельное ядро ​​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"));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...