Nommer les threads et les pools de threads D'ExecutorService

disons que j'ai une application qui utilise le cadre Executor comme tel

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

lorsque j'exécute cette application dans le débogueur, un thread est créé avec le nom (par défaut) suivant: Thread[pool-1-thread-1] . Comme vous pouvez le voir, ce n'est pas très utile et pour autant que je puisse dire, le cadre Executor ne fournit pas un moyen facile de nommer les threads créés ou les thread-pools.

alors, comment va-t-on fournir des noms pour threads/thread-piscines? Par exemple, Thread[FooPool-FooThread] .

170
demandé sur Ravindra babu 2011-05-24 20:33:46

14 réponses

vous pourriez fournir un ThreadFactory à newSingleThreadScheduledExecutor(ThreadFactory threadFactory) . L'usine sera responsable de la création des threads, et pourra les nommer.

pour citer le Javadoc :

créer de nouveaux fils

nouveaux threads sont créés en utilisant un ThreadFactory . Si non spécifié ailleurs, un Executors.defaultThreadFactory() est utilisé, qui crée les fils à tous être dans le même ThreadGroup et avec le même NORM_PRIORITY priorité et le statut non-daemon. En fournissant un ThreadFactory différent , vous pouvez modifier le nom du thread, le groupe de thread, la priorité, l'état du démon, etc. Si un ThreadFactory ne crée pas de thread lorsqu'on le lui demande en retournant null De newThread , l'exécuteur continuera, mais pourrait ne pas être en mesure d'exécuter des tâches

93
répondu NPE 2016-09-02 09:37:16

la goyave a presque toujours ce qu'il faut besoin .

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

et passez-le à votre ExecutorService .

230
répondu pathikrit 2018-01-21 17:29:27

vous pouvez essayer de fournir votre propre usine de fil, qui créera fil avec des noms appropriés. Voici un exemple:

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

Executors.newSingleThreadExecutor(new YourThreadFactory()).submit(someRunnable);
69
répondu Nikita Beloglazov 2015-04-29 22:46:24

vous pouvez aussi changer le nom de votre thread par la suite, pendant que le thread est exécuté:

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

cela pourrait être intéressant si par exemple vous utilisez le même ThreadFactory pour différents types de tâches.

42
répondu FlorianT 2013-10-31 10:05:57

Le BasicThreadFactory à partir de apache commons-lang est également utile de prévoir la désignation de comportement. Au lieu d'écrire une classe interne anonyme, vous pouvez utiliser le constructeur pour nommer les fils comme vous voulez. Voici l'exemple de 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);
39
répondu scompt.com 2014-05-09 11:29:07

il y a un open RFE pour cela avec Oracle. D'après les commentaires de L'employé D'Oracle, il semble qu'ils ne comprennent pas le problème et ne vont pas le résoudre. C'est une de ces choses qui est très simple à supporter dans le JDK (sans briser la compatibilité en arrière) donc c'est un peu dommage que le RFE soit mal compris.

comme indiqué, vous devez mettre en œuvre votre propre ThreadFactory . Si vous ne voulez pas tirer dans le Guava ou Apache Commons juste pour cela je fournis ici une implémentation ThreadFactory que vous pouvez utiliser. Il est exactement similaire à ce que vous obtenez du JDK sauf pour la possibilité de définir le préfixe du nom de thread à autre chose que "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;
    }
}

quand vous voulez l'utiliser vous profitez simplement du fait que toutes les méthodes Executors vous permettent de fournir votre propre ThreadFactory .

Ce

    Executors.newSingleThreadExecutor();

donnera un Exécutorservice où les threads sont nommés pool-N-thread-M mais en utilisant

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

vous obtiendrez un Exécutorservice où les threads sont nommés primecalc-N-thread-M . Voila!

17
répondu peterh 2015-05-16 18:52:16

si vous utilisez Spring, il y a CustomizableThreadFactory pour lequel vous pouvez définir un préfixe de nom de fil.

exemple:

ExecutorService alphaExecutor =
    Executors.newFixedThreadPool(10, new CustomizableThreadFactory("alpha-"));
13
répondu Adam Michalik 2018-03-20 12:24:02
private class TaskThreadFactory implements ThreadFactory
{

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

        return t;
    }

}

passez le ThreadFactory à un executorservice et vous êtes bon à aller

8
répondu I.Tyger 2014-01-08 18:16:39

un moyen rapide et sale est d'utiliser Thread.currentThread().setName(myName); dans la méthode run() .

6
répondu Kirk 2015-04-29 15:25:30

Extend ThreadFactory

public interface ThreadFactory

un objet qui crée de nouveaux threads à la demande. L'utilisation des usines de fil élimine le durcissement des appels à nouveau fil, permettant aux applications d'utiliser des sous-classes spéciales de fil, des priorités, etc.

Thread newThread(Runnable r)

construit un nouveau Thread. Les implémentations peuvent aussi initialiser la priorité, le nom, le statut de démon, le ThreadGroup, etc.

code échantillon:

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

sortie:

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

5
répondu Ravindra babu 2016-11-03 12:04:36
Executors.newSingleThreadExecutor(r -> new Thread(r, "someName")).submit(getJob());

Runnable getJob() {
        return () -> {
            // your job
        };
}
3
répondu many mny 2016-12-03 23:25:22

vous pouvez écrire votre propre implémentation de ThreadFactory, en utilisant par exemple une implémentation existante (comme defaultThreadFactory) et changer le nom à la fin.

exemple de mise en œuvre de 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;
    }
}

et usage:

Executors.newSingleThreadExecutor(new ThreadFactoryWithCustomName(
        Executors.defaultThreadFactory(),
        "customName")
    );
3
répondu K. Gol 2017-02-06 10:25:41

c'est mon usine personnalisée fournissant un nom personnalisé pour les analyseurs de dump filetage. En général, je donne juste tf=null pour réutiliser JVM default thread factory. ce site Web a plus avancé l'usine de fil.

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

pour votre commodité il s'agit d'une boucle de vidage de thread à des fins de débogage.

    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()
            );
        }
    }
3
répondu Whome 2017-08-25 13:34:11

j'ai l'habitude de faire la même chose comme ci-dessous:

ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("SO-POOL-%d").build();
ExecutorService executorService = Executors.newFixedThreadPool(5,namedThreadFactory);
0
répondu bittu 2018-08-07 09:45:40