Nombres de subprocesos y grupos de subprocesos de ExecutorService


Digamos que tengo una aplicación que utiliza el marco Executor como tal

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

Cuando corro esta aplicación en el depurador, se crea un subproceso con el siguiente nombre (predeterminado): Thread[pool-1-thread-1]. Como puedes ver, esto no es terriblemente útil y por lo que puedo decir, el marco Executor no proporciona una manera fácil de nombrar los subprocesos o grupos de subprocesos creados.

Entonces, ¿cómo se puede proporcionar nombres para los subprocesos/conjuntos de subprocesos? Por ejemplo, Thread[FooPool-FooThread].

Author: Ravindra babu, 2011-05-24

14 answers

Usted podría proporcionar un ThreadFactory to newSingleThreadScheduledExecutor(ThreadFactory threadFactory). La fábrica será responsable de crear hilos, y podrá nombrarlos.

Para citar el Javadoc :

Creando nuevos hilos

Se crean nuevos hilos usando un ThreadFactory. Si no se especifica lo contrario, se usa un Executors.defaultThreadFactory(), que crea subprocesos para que todos estén en el mismo ThreadGroup y con la misma prioridad NORM_PRIORITY y estado no demonio. Al suministrar un ThreadFactory diferente, puede alterar el nombre del subproceso, grupo de subprocesos, prioridad, estado del demonio, etc. Si un ThreadFactory no puede crear un hilo cuando se le pide devolver null desde newThread, el ejecutor continuará, pero podría no ser capaz de ejecutar ninguna tarea

 93
Author: NPE,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-02 09:37:16

La guayaba casi siempre tiene lo que usted necesita.

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

Y pasárselo a su ExecutorService.

 230
Author: pathikrit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-21 17:29:27

Puede intentar proporcionar su propia fábrica de hilos, que creará hilos con los nombres apropiados. He aquí un ejemplo:

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

Executors.newSingleThreadExecutor(new YourThreadFactory()).submit(someRunnable);
 69
Author: Nikita Beloglazov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-29 22:46:24

También puedes cambiar el nombre de tu hilo después, mientras se ejecuta el hilo:

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

Eso podría ser de interés si, por ejemplo, está utilizando la misma ThreadFactory para diferentes tipos de tareas.

 42
Author: FlorianT,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-31 10:05:57

El BasicThreadFactory desde apache commons-lang también es útil para proporcionar el comportamiento de nomenclatura. En lugar de escribir una clase interna anónima, puedes usar el Constructor para nombrar los hilos como quieras. Este es el ejemplo de los 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
Author: scompt.com,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-05-09 11:29:07

Hay un open RFE para esto con Oracle. A partir de los comentarios del empleado de Oracle, parece que no entienden el problema y no lo solucionarán. Es una de estas cosas que es muy fácil de soportar en el JDK (sin romper la compatibilidad hacia atrás) por lo que es una pena que el RFE se malinterprete.

Como se ha señalado, debe implementar su propia ThreadFactory. Si no quieres tirar de Guayaba o Apache Commons solo para este propósito, te proporciono aquí una implementación ThreadFactory que puede usar. Es exactamente similar a lo que obtienes del JDK, excepto por la capacidad de establecer el prefijo del nombre del hilo en algo más 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;
    }
}

Cuando quiera usarlo, simplemente aproveche el hecho de que todos los métodos Executors le permiten proporcionar su propio ThreadFactory.

Esto

    Executors.newSingleThreadExecutor();

Dará un ExecutorService donde los hilos se nombran pool-N-thread-M pero usando

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

Obtendrá un ExecutorService donde se encuentran los subprocesos nombrado primecalc-N-thread-M. ¡Voila!

 17
Author: peterh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-16 18:52:16

Si usted está usando la primavera, hay CustomizableThreadFactory para lo cual puede establecer un prefijo de nombre de hilo.

Ejemplo:

ExecutorService alphaExecutor =
    Executors.newFixedThreadPool(10, new CustomizableThreadFactory("alpha-"));
 13
Author: Adam Michalik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
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;
    }

}

Pase la ThreadFactory a un executorservice y estará listo

 8
Author: I.Tyger,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-01-08 18:16:39

Una forma rápida y sucia es usar Thread.currentThread().setName(myName); en el método run().

 6
Author: Kirk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-29 15:25:30

Extender ThreadFactory

public interface ThreadFactory

Un objeto que crea nuevos hilos bajo demanda. El uso de fábricas de subprocesos elimina el cableado de llamadas a nuevos subprocesos, lo que permite a las aplicaciones utilizar subclases de subprocesos especiales, prioridades, etc.

Thread newThread(Runnable r)

Construye un nuevo Hilo. Las implementaciones también pueden inicializar priority, name,daemon status, ThreadGroup, etc.

Muestra código:

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

Salida:

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
Author: Ravindra babu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-03 12:04:36
Executors.newSingleThreadExecutor(r -> new Thread(r, "someName")).submit(getJob());

Runnable getJob() {
        return () -> {
            // your job
        };
}
 3
Author: many mny,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-03 23:25:22

Puede escribir su propia implementación de ThreadFactory, usando por ejemplo alguna implementación existente (como defaultThreadFactory) y cambiar el nombre al final.

Ejemplo de implementación 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;
    }
}

Y uso:

Executors.newSingleThreadExecutor(new ThreadFactoryWithCustomName(
        Executors.defaultThreadFactory(),
        "customName")
    );
 3
Author: K. Gol,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-06 10:25:41

Esta es mi fábrica personalizada que proporciona nombres personalizados para analizadores de volcado de hilo. Por lo general, solo doy tf=null para reutilizar la fábrica de subprocesos predeterminada de JVM. Este sitio web tiene una fábrica de hilos más avanzada.

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

Para su comodidad, este es un bucle de volcado de subprocesos para fines de depuración.

    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
Author: Whome,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-25 13:34:11

Uso para hacer lo mismo como a continuación:

ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("SO-POOL-%d").build();
ExecutorService executorService = Executors.newFixedThreadPool(5,namedThreadFactory);
 0
Author: bittu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-07 09:45:40