2010-07-12 25 views
32

Estoy ejecutando un objeto que se puede llamar utilizando grupo de subprocesos ExecutorService. Quiero dar un nombre a este hilo.¿Cómo dar nombre a un hilo invocable?

Para ser más específicos, en la versión anterior que hice esto -

Thread thread = new Thread(runnable Task); 
thread.setName("My Thread Name"); 

utilizo hilo nombre en el registro de log4j, esto ayuda mucho mientras la solución de problemas. Ahora estoy migrando mi código de Java 1.4 a Java 1.6. He escrito esto (dado a continuación), pero no sé cómo dar nombre a este hilo.

private final ExecutorService executorPool = Executors.newCachedThreadPool(); 
Future<String> result = executorPool.submit(callable Task); 

Por favor, ¿me das alguna idea para ponerle nombre a este hilo?

+0

eche un vistazo a ['VerboseThreads'] (http://www.jcabi.com/jcabi-log/threads-VerboseThreads.html), esta fábrica nombra los hilos automáticamente utilizando el prefijo proporcionado – yegor256

+1

TL; DR Respuesta: http: //stackoverflow.com/a/9748697/231917 – zengr

Respuesta

28

Usted puede utilizar el método sobrecargado:

java.util.concurrent.Executors.newCachedThreadPool(ThreadFactory) 

que le permite pasar una

java.util.concurrent.ThreadFactory 

que deberían permitirle fijar nombres del hilo a través de java.util.concurrent.ThreadFactory.newThread(Runnable):

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

Tenga una mirada en java.util.concurrent.Executors.DefaultThreadFactory para una implementación por defecto.

Adición

ya que veo que este hilo todavía es visitado, guayaba (si lo tiene disponible) proporciona una ThreadFactoryBuilder que aprovecha la necesidad de tener una clase anónima interna e incluso permite la personalización de los nombres parametrizados para tus hilos

+0

ThreadFactory.newThread (ejecutable), pero mi tarea es invocable ...! – user381878

+5

Su 'Callable' se ajustará a' java.util.concurrent.FutureTask' que implementa 'java.util.concurrent.RunnableFuture' que implementa' Runnable'. Por otro lado, no tendría mucho sentido que 'ThreadFactory' permita la creación de subprocesos solo para' Runnable's mientras que 'ExecutorService' permite la presentación de' Callable's. – Andreas

+3

gracias por su sugerencia - He encontrado otra alternativa para hacer eso - Estoy poniendo esto como primera línea de mi hilo - Thread.currentThread(). SetName (this.client.getIdentityString()); – user381878

8

Debe tener cuidado al renombrar subprocesos cuando sus subprocesos son administrados por un grupo de subprocesos porque en realidad se están reutilizando una y otra vez para tareas diferentes y una vez renombrado, puede encontrar que los nombres de subproceso en sus registros no t tiene ningún sentido ... con el fin de evitar que la conducta no deseada que debe asegurarse de que una vez que su Ejecutable/rescatable terminó el nombre del hilo se restaura.

Una forma de implementar esto es, envolviendo cada Ejecutable/rescatable que es ejecutado por el hilo-piscina con un decorador que se ocupa de todas las necesarias limpiezas.

10
/** 
* The default thread factory 
*/ 
static class DefaultThreadFactory implements ThreadFactory { 
    static final AtomicInteger poolNumber = new AtomicInteger(1); 
    final ThreadGroup group; 
    final AtomicInteger threadNumber = new AtomicInteger(1); 
    final String namePrefix; 

    DefaultThreadFactory() { 
     SecurityManager s = System.getSecurityManager(); 
     group = (s != null)? s.getThreadGroup() : 
          Thread.currentThread().getThreadGroup(); 
     namePrefix = "pool-" + 
         poolNumber.getAndIncrement() + 
        "-thread-"; 
    } 

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

Esta es la implementación original en Java 1.5.0. Entonces, en realidad tiene los nombres de pool-x-thread donde x representa el orden del hilo en el grupo de hilos actual.

+0

¡Esto funcionó perfectamente! Gracias. – PerwinCZ

34

actualmente estoy haciendo algo como esto:

someExecutor.execute(new Runnable() { 
     @Override public void run() { 
      final String orgName = Thread.currentThread().getName(); 
      Thread.currentThread().setName(orgName + " - My custom name here"); 
      try { 
       myAction(); 
      } finally { 
       Thread.currentThread().setName(orgName); 
      } 
     } 
    }); 
+4

esto es simple y fácil, pero dado que se revierte al nombre predeterminado del subproceso al final de 'run()', solo verá su nombre personalizado mientras 'run()' se está ejecutando. para la ejecución programada de tareas a corto plazo, verá el nombre predeterminado en el depurador la mayor parte del tiempo. – ericsoco

+0

¡La guayaba debe (pero no parece) tener un método de utilidad! – btiernay

+0

solo para que quede claro, no olviden el bloque finally .... – Gab

2

sólo tenía que hacer lo que usted está pidiendo - proporcionar nombres a mis grupos de hilos - así que gracias a la respuesta de Andeas, he creado mi propia ThreadFactory como una clase interna de la clase que se va a usar copiando los ejecutores $ DefaultThreadFactory, el cambio de 3 líneas añadiendo el parámetro "nombre de grupo" para el constructor.

/** 
* A thread factory that names each thread with the provided group name. 
* <p> 
* Except lines with "elarson modified", copied from code 
* Executors$DefaultThreadFactory -- Doug Lea, Copyright Oracle, et al. 
*/ 
static class GroupNameThreadFactory implements ThreadFactory { 
    private String groupname; /* elarson modified */ 
    private static final AtomicInteger poolNumber = new AtomicInteger(1); 
    private final ThreadGroup group; 
    private final AtomicInteger threadNumber = new AtomicInteger(1); 
    private final String namePrefix; 

    GroupNameThreadFactory(String groupname) { 
     this.groupname = groupname; /* elarson modified */ 
     SecurityManager s = System.getSecurityManager(); 
     group = (s != null) ? s.getThreadGroup() : 
           Thread.currentThread().getThreadGroup(); 
     namePrefix = "pool-" + 
         this.groupname + /* elarson modified */ 
         poolNumber.getAndIncrement() + 
        "-thread-"; 
    } 

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

La creación de un ThreadPool se realiza de la siguiente manera.

 ThreadFactory threadfactory = new GroupNameThreadFactory("Monitor");  
    executor = Executors.newFixedThreadPool(NUM_THREADS, threadfactory); 

Gracias user381878 por hacer la pregunta, y Andreas por la respuesta.

0

Hay que crear una ThreadFactory anónimo para conseguir el servicio Ejecutor. ThreadFactory puede proporcionar el nombre del subproceso de la siguiente manera: "Subproceso A" o "Subproceso B" (consulte el ejemplo).

luego llamar a la tarea exigible utilizando los diferentes servicios de Ejecutor:

ejemplo de la clase:

ThreadTester public class {

public static void main(String[] args) { 
    ThreadTester threadTester = new ThreadTester(); 
    threadTester.test(); 
} 

private void test() { 

    ExecutorService executorservice = Executors.newCachedThreadPool(new ThreadFactory() { 

     @Override 
     public Thread newThread(Runnable arg0) { 
      return new Thread(arg0,"Thread A"); 
     } 
    }); 

    CallableTask taskA = new CallableTask(); 
    executorservice.submit(taskA); 

    executorservice = Executors.newCachedThreadPool(new ThreadFactory() { 

     @Override 
     public Thread newThread(Runnable arg0) { 
      return new Thread(arg0,"Thread B"); 
     } 
    }); 
    CallableTask taskB = new CallableTask(); 
    executorservice.submit(taskB); 
} 

}

redimible de la tarea:

pública class CallableTask implementa Callable {

@Override 
public Integer call() throws Exception { 
    int sum = 0; 

    for(int count=1;count<=30;count++){ 
     try { 
      Thread.sleep(300); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
     System.out.println(Thread.currentThread().getName() + " Count :"+count); 
     sum = sum + count; 
    } 
    System.out.println(Thread.currentThread().getName() + " Sum :"+sum); 
    return sum; 
} 

}

0

Un método que he utilizado, y en mi caso he tenido una serie de futuros de ir a buscar los datos en paralelo controlado por una sola clase. Presento una cantidad de trabajos y recupero el futuro. Guardo el futuro en un mapa con el valor como nombre del trabajo. Luego, cuando estoy obteniendo un tiempo de espera en todos los futuros, tengo el nombre del trabajo del mapa. No es quizás la forma más flexible, pero funcionó en mi situación.

Cuestiones relacionadas