resueltos hilos ejemplos ejemplo java threadpool runnable executorservice managedthreadfactory

ejemplos - hilos spring java



Nombrar hilos y grupos de hilos de ExecutorService (13)

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 ejecuto esta aplicación en el depurador, se crea un subproceso con el siguiente nombre (predeterminado): 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] .


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


Extender ThreadFactory

public interface ThreadFactory

Un objeto que crea nuevos hilos a pedido. El uso de fábricas de subprocesos elimina el cableado de las llamadas al nuevo subproceso, permitiendo que las aplicaciones usen subclases de subprocesos especiales, prioridades, etc.

Thread newThread(Runnable r)

Construye un nuevo hilo. Las implementaciones también pueden inicializar prioridad, nombre, estado del daemon, ThreadGroup, etc.

Código de muestra:

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


Guava casi siempre tiene lo que need .

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

y pasarlo a su ExecutorService .


Hay una RFE abierta 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 propia ThreadFactory . Si no desea utilizar Guava o Apache Commons solo para este fin, 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 quiera usarlo, simplemente aproveche el hecho de que todos los métodos de los Executors permiten proporcionar su propio ThreadFactory .

Esta

Executors.newSingleThreadExecutor();

dará un ExecutorService donde los hilos se denominan pool-N-thread-M pero al usar

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

obtendrá un ExecutorService donde los hilos se denominan primecalc-N-thread-M . Voila!


Puede escribir su propia implementación de ThreadFactory, utilizando, por ejemplo, alguna implementación existente (como por ejemplo, DefaultHhreadFactory) 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 el uso:

Executors.newSingleThreadExecutor(new ThreadFactoryWithCustomName( Executors.defaultThreadFactory(), "customName") );


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

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


Puede suministrar un ThreadFactory a newSingleThreadScheduledExecutor(ThreadFactory threadFactory) . La fábrica será responsable de crear hilos y podrá nombrarlos.

Para citar el Javadoc :

Creando nuevos hilos

Los nuevos hilos se crean usando ThreadFactory . Si no se especifica lo contrario, se utiliza Executors.defaultThreadFactory() , que crea subprocesos para que todos estén en el mismo ThreadGroup y con la misma prioridad NORM_PRIORITY y el estado no-demonio. Al suministrar un ThreadFactory diferente, puede alterar el nombre del hilo, el grupo de hilos, la prioridad, el estado del daemon, etc. Si un ThreadFactory no puede crear un hilo cuando se le pregunta al devolver null desde newThread , el ejecutor continuará, pero es posible que no pueda ejecutar cualquier tarea


Si está utilizando Spring, hay CustomizableThreadFactory para el cual puede establecer un prefijo de nombre de hilo.

Ejemplo:

ExecutorService alphaExecutor = Executors.newFixedThreadPool(10, new CustomizableThreadFactory("alpha-"));


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

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

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


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


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


Executors.newSingleThreadExecutor(r -> new Thread(r, "someName")).submit(getJob()); Runnable getJob() { return () -> { // your job }; }


private class TaskThreadFactory implements ThreadFactory { @Override public Thread newThread(Runnable r) { Thread t = new Thread(r, "TASK_EXECUTION_THREAD"); return t; } }

Pase ThreadFactory a un ejecutorservice y está listo para ir