2011-05-24 11 views
147

Digamos que tengo una aplicación que utiliza el marco Executor como talhilos de nomenclatura y conjuntos de hilos-piscinas de ExecutorService

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

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

Entonces, ¿cómo hace uno para proporcionar nombres para los subprocesos/subprocesos? Por ejemplo, Thread[FooPool-FooThread].

Respuesta

80

Usted podría suministrar una ThreadFactory-newSingleThreadScheduledExecutor(ThreadFactory threadFactory). La fábrica será responsable de crear hilos y podrá nombrarlos.

citar el Javadoc:

Creación de nuevos temas

nuevos hilos son creados usando una ThreadFactory. Si no se especifica lo contrario, se utiliza un Executors.defaultThreadFactory(), que crea subprocesos para que todos estén en el mismo ThreadGroup y con el mismo estado de prioridad y no de demonio NORM_PRIORITY. Al proporcionar un ThreadFactory diferente, puede modificar el nombre del subproceso, el grupo de subprocesos, la prioridad, el estado del daemon, etc. Si un ThreadFactory falla al crear un subproceso cuando se le pregunta al devolver nulo desde newThread, el ejecutor continuará pero no podrá ejecutar cualquier tarea

63

Puede intentar proporcionar su propia fábrica de hilos, que creará un hilo 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); 
39

El BasicThreadFactory de Apache commons-lang también es útil para proporcionar el comportamiento de nomenclatura. En lugar de escribir una clase interna anónima, puede usar el Creador para nombrar los hilos como desee. Aquí está 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); 
198

guayaba casi siempre tiene lo que need.

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

y pásalo a tu ExecutorService.

+0

¡Eso es fantástico! –

37

También puede cambiar el nombre de su hilo después, mientras se ejecuta el hilo:

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

que podrían ser de interés si por ejemplo estás usando el mismo ThreadFactory para diferentes tipos de tareas.

+5

Esto funcionó bien porque, como FlorianT describió, tengo muchos tipos diferentes de subprocesos y no quería tener que crear múltiples objetos ThreadFactory solo para el nombre. Llamé a Thread.currentThread(). SetName ("FooName"); como la primera línea en cada método run(). –

+5

Un problema menor con esto es cuando ocurre el comportamiento de falla descrito en los documentos: '(Sin embargo, si este solo subproceso finaliza debido a un error durante la ejecución antes del apagado, uno nuevo tomará su lugar si es necesario para ejecutar tareas posteriores .) '. Si el ExecutorService reemplaza el hilo, será nombrado por ThreadFactory. Por otra parte, ver el nombre desaparecer mientras la depuración podría ser un indicador útil. – sethro

+0

¡Simplemente excelente! Gracias. – asgs

8
private class TaskThreadFactory implements ThreadFactory 
{ 

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

     return t; 
    } 

} 

Pasar el ThreadFactory a un ExecutorService y que son buenos para ir

6

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

15

Hay un open RFE para esto con Oracle. De los comentarios del empleado de Oracle parece que no entienden el problema y no lo arreglará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 sea mal entendido.

Como se señaló, debe implementar su propio ThreadFactory. Si no desea obtener en Guava o Apache Commons solo para este propósito, proporciono aquí una implementación de 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 "grupo".

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 se desea utilizarlo simplemente tomar ventaja del hecho de que todos los Executors métodos permiten que proporcione su propia ThreadFactory.

Este

Executors.newSingleThreadExecutor(); 

dará una ExecutorService donde las discusiones se nombran pool-N-thread-M pero usando

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

obtendrá un ExecutorService donde las discusiones se nombran primecalc-N-thread-M. Voila!

5

Extender ThreadFactory

public interface ThreadFactory

Un objeto que crea nuevos temas bajo demanda. El uso de las fábricas de hilo elimina cableado de las llamadas a la nueva rosca, que permite a las aplicaciones utilizar subclases de rosca especiales, prioridades, etc.

Thread newThread(Runnable r)

construye un nuevo hilo. Implementaciones también pueden inicializar prioridad, nombre, estado daemon, ThreadGroup, etc.

Código de ejemplo:

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

de 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

+1

El contador de subprocesos no es seguro para subprocesos: debe usar un AtomicInteger. – Pino

+0

Gracias por su sugerencia. He incorporado tu sugerencia. –

2
Executors.newSingleThreadExecutor(r -> new Thread(r, "someName")).submit(getJob()); 

Runnable getJob() { 
     return() -> { 
      // your job 
     }; 
} 
2

Puede escribir su propia implementación de ThreadFactory, utilizando para ejemplo alguna implementación existente (como defaultThreadFactory) y cambie 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

Esta es mi fábrica personalizada que proporciona un nombres personalizados para analizadores de volcado de hilo. Por lo general, solo doy tf=null para reutilizar la fábrica de hilos por defecto de JVM. 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")); 

Para su comodidad este es un bucle de hilo de volcado 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() 
      ); 
     } 
    } 
+0

Esto funcionó muy bien para mí, algo sorprendido de que no haya sido votado mucho. De cualquier forma, salud. – codedcosmos

Cuestiones relacionadas