2011-12-15 17 views
9

Estoy usando un ThreadPoolExecutor en Java para administrar una gran cantidad de subprocesos en ejecución. Creé mi propio ThreadFactory simple para que pueda darle a los hilos mejores nombres.Con ThreadPoolExecutor, ¿cómo obtener el nombre del subproceso que se ejecuta en el grupo de subprocesos?

El problema es que el nombre se establece en el subproceso cuando se crea el grupo de subprocesos por primera vez y no está vinculado a la tarea en la que se está ejecutando realmente el grupo de subprocesos. Entiendo esto ... mis Runnables y Callables, aunque tienen nombres, son en realidad un nivel de abstracción de los hilos en ejecución de ThreadPoolExecutor.

Ha habido algunas otras preguntas sobre StackOverflow sobre cómo crear nombres para ThreadPoolExecutor grupos de hilos. (Consulte How to give name to a callable Thread? y How to name the threads of a thread pool in Java.)

Lo que quiero saber es: ¿Alguien tiene una buena solución para mantener el nombre del hilo del grupo de subprocesos sincronizado con el Runnable que se está ejecutando realmente?

es decir, Si llamo Thread.getCurrentThread().getName() me gustaría que no para devolver el nombre de la agrupación de hebras de nivel superior, sino más bien el nombre de la Callable/Ejecutable que el hilo se está ejecutando actualmente.

Dado que esto es principalmente para fines de depuración y registro, estoy tratando de evitar una solución que implique que coloque un nuevo código en cada Runnable que pueda enviarse al ThreadPoolExecutor - Prefiero poner un código en el ThreadFactory o envuelva el ThreadPoolExecutor mismo para que el cambio se realice en un solo lugar. Si tal solución no existe, probablemente no me moleste, ya que no es una misión crítica.

comienzan edición Para aclarar, sé que puedo poner un Thread.currentThread().setName("my runnable name"); como la primera línea del método run de cada Ejecutable, pero estoy tratando de evitar hacer eso. Estoy siendo un perfeccionista aquí, y me doy cuenta, así que no me ofenderé si la gente quiere hacer un comentario sobre esta pregunta y dímelo. final de edición

Mi otra pregunta, supongo, es si la gente piensa que es una mala idea para hacer tal cosa. ¿Debo tener cuidado de actualizar el nombre del grupo de subprocesos de esta manera?

¡Gracias por cualquier sugerencia!

+0

"manteniendo el nombre de la rosca grupo de subprocesos en sincronía con el Ejecutable que realmente se está ejecutando" -> Ejecutable/rescatable no define un nombre, por lo que no puede ver bien el empuje de su pregunta . ¿Su ThreadFactory realmente le da a cada hilo un nombre distinto? – serg10

+0

Correcto, cada uno de mis Runnables y Callables implementan una interfaz con nombre, así que tengo acceso a los nombres. Me doy cuenta de que soy exigente porque ya he implementado una función especial para todos mis Runnables, pero quiero evitar agregar código adicional que establece manualmente el nombre de la secuencia. –

+1

Editado para mayor claridad, cambiando algunos "grupos de hilos" a "hilos", y algunos "hilos" a "tareas". –

Respuesta

13

Cree un ThreadPoolExecutor que anule el método beforeExecute.

private final ThreadPoolExecutor executor = new ThreadPoolExecutor (new ThreadPoolExecutor(10, 10, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()){ 
    protected void beforeExecute(Thread t, Runnable r) { 
     t.setName(deriveRunnableName(r)); 
    } 

    protected void afterExecute(Runnable r, Throwable t) { 
     Thread.currentThread().setName(""); 
    } 

    protected <V> RunnableFuture<V> newTaskFor(final Runnable runnable, V v) { 
     return new FutureTask<V>(runnable, v) { 
      public String toString() { 
       return runnable.toString(); 
      } 
     }; 
    }; 
} 
No

seguro de cómo funcionaría exactamente derveRunnableName(), tal vez toString()?

Editar: El Thread.currentThread() es, de hecho, el hilo que se establece en beforeExecute que llama al afterExecute. Puede hacer referencia a Thread.currentThread() y luego establecer el nombre en AfterExecute.Esto se nota en los javadocs

/** 
* Method invoked upon completion of execution of the given Runnable. 
* This method is invoked by the thread that executed the task. If 
* non-null, the Throwable is the uncaught <tt>RuntimeException</tt> 
* or <tt>Error</tt> that caused execution to terminate abruptly. 
* 
* <p><b>Note:</b> When actions are enclosed in tasks (such as 
* {@link FutureTask}) either explicitly or via methods such as 
* <tt>submit</tt>, these task objects catch and maintain 
* computational exceptions, and so they do not cause abrupt 
* termination, and the internal exceptions are <em>not</em> 
* passed to this method. 
* 
* <p>This implementation does nothing, but may be customized in 
* subclasses. Note: To properly nest multiple overridings, subclasses 
* should generally invoke <tt>super.afterExecute</tt> at the 
* beginning of this method. 
* 
* @param r the runnable that has completed. 
* @param t the exception that caused termination, or null if 
* execution completed normally. 
*/ 
protected void afterExecute(Runnable r, Throwable t) { } 

Editar El TPE se envuelva el Ejecutable dentro de un FutureTask, por lo que para apoyar el método toString que podría invalidar newTaskFor y crear su propia FutureTask envueltos.

+0

En realidad estoy intentando algo como esto en este momento, tan buena sugerencia. El único problema es cuando se completa Runnable, el grupo de subprocesos todavía tiene ese nombre. Lamentablemente, el método afterExecute reemplazable no obtiene el subproceso en el que se ejecutó Runnable. Me gustaría poder limpiarlo cuando termine también. –

+1

@JeffGoldberg En afterExecute, Thread.currentThread() es en realidad el hilo en el que estoy estableciendo el nombre beforeExecute. Actualizaré mi respuesta para demostrar esto. –

+0

Impresionante, esto es genial. ¡Gracias! –

2

Mi sugerencia sería tratar

pool.execute(new Runnable() { 
    public void run() { 
     Thread.getCurrentThread().setName("My descriptive Runnable"); 
     // do my descriptive Runnable 
    } 
});     

También puede restablecer el nombre cuando haya terminado, si quieres.

+0

¿Está sugiriendo que haga esto cada vez que llamo a pool.execute o que anulo el método de ejecución del conjunto? –

+0

Suponiendo que desea cambiar el nombre para reflejar lo que está haciendo ese hilo, sí. Nota: cambiará cuando se inicie Runnable, no cuando llame a invocar. ;) –

4

Entonces, tengo una solución que maneja tanto para establecer el nombre como para limpiar después del nombre. Gracias a Peter Lawrey y John Vint por sus sugerencias que me llevaron aquí. Como ninguna de las dos sugerencias resolvió completamente mi problema, pensé que publicaría este código de muestra como una respuesta separada. Me disculpo si eso es mala etiqueta, si es así, háganmelo saber y me adaptaré.

En el siguiente código decidí mantener el nombre del subproceso ThreadPoolExecutor original y anexar el nombre Runnable, luego en el bloque finally eliminar el nombre Runnable para limpiar, pero eso se puede modificar fácilmente.

Como John Vint sugiere, preferiría reemplazar el método beforeExecution y luego reemplazar el método afterExecution para limpiar, pero el afterExecution no tiene un identificador para el hilo.

public class RunnableNameThreadPoolExecutor extends ThreadPoolExecutor { 

    /* Constructors... */ 

    @Override 
    public void execute(Runnable command) { 
     super.execute(new ManageNameRunnable(command)); 
    } 

    private class ManageNameRunnable implements Runnable { 
     private final Runnable command; 
     ManageNameRunnable(Runnable command) { 
      this.command = command; 
     } 

     public void run() { 
      String originalName = Thread.currentThread().getName(); 
      try { 
       String runnableName = getRunnableName(command); 
       Thread.currentThread().setName(originalName+ ": " + runnableName); 
       command.run(); 
      } finally { 
       Thread.currentThread().setName(originalName); 
      } 
     } 
    } 
} 
+1

¿tiene más código de trabajo? como la definición getRunnableName() y el código de llamada de muestra? – peterboston

Cuestiones relacionadas