Именование потоков и пулов потоков 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 ]

251 голосов
/ 17 марта 2012

Гуава почти всегда имеет то, что вам нужно .

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

и передайте его вашему ExecutorService.

105 голосов
/ 24 мая 2011

Вы можете указать ThreadFactory для newSingleThreadScheduledExecutor(ThreadFactory threadFactory).Фабрика будет отвечать за создание потоков и сможет называть их.

Цитировать Javadoc :

Создание новых потоков

Новые темы создаются с использованием ThreadFactory.Если не указано иное, используется Executors.defaultThreadFactory(), который создает все потоки с одинаковым ThreadGroup и одинаковым приоритетом NORM_PRIORITY и статусом, не являющимся демоном.Предоставляя другой ThreadFactory, вы можете изменить имя потока, группу потоков, приоритет, состояние демона и т. Д. Если ThreadFactory не удается создать поток при запросе, возвращая ноль из newThread, исполнитель продолжит,но не может быть в состоянии выполнить какие-либо задачи

86 голосов
/ 24 мая 2011

Вы можете попытаться указать собственную фабрику потоков, которая будет создавать потоки с соответствующими именами.Вот один пример:

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

Executors.newSingleThreadExecutor(new YourThreadFactory()).submit(someRunnable);
49 голосов
/ 31 октября 2013

Вы также можете впоследствии изменить имя своего потока, пока поток выполняется:

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

Это может быть интересно, если, например, вы используете один и тот же ThreadFactory для задач другого типа.

46 голосов
/ 25 мая 2011

BasicThreadFactory от apache commons-lang также полезен для обеспечения поведения именования. Вместо того, чтобы писать анонимный внутренний класс, вы можете использовать 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);
19 голосов
/ 16 мая 2015

Для Oracle есть открытый 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"));

вы получите ExecutorService, где потоки названы primecalc-N-thread-M.Voila!

17 голосов
/ 07 января 2016

Если вы используете Spring, существует CustomizableThreadFactory, для которого вы можете установить префикс имени потока.

Пример:

ExecutorService alphaExecutor =
    Executors.newFixedThreadPool(10, new CustomizableThreadFactory("alpha-"));
8 голосов
/ 08 января 2014
private class TaskThreadFactory implements ThreadFactory
{

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

        return t;
    }

}

Передайте ThreadFactory в службу executor, и все готово

6 голосов
/ 05 февраля 2016

Расширение ThreadFactory

public interface ThreadFactory

Объект, который создает новые потоки по требованию. Использование фабрик потоков устраняет жесткую привязку вызовов к новому потоку, позволяя приложениям использовать специальные подклассы потоков, приоритеты и т. Д.

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

.... и т. Д.

6 голосов
/ 18 июля 2014

Быстрый и грязный способ - использовать Thread.currentThread().setName(myName); в методе run().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...