Cómo verificar el estado de ExecutorService
I.Crear una tarea
Una tarea es una clase que implementa la interfaz Runnable.
Crear el método de ejecución real puede ser:
1.
2. Ejecución de la tarea
La tarea se realiza a través de java.util. Se ejecuta el objeto de interfaz concurrent.ExecutorService, que se crea mediante el método estático de la clase de herramienta java.util.concurrent.Executors.
Executors Factory y métodos de utilidad para las clases Executor, ExecutorService, ScheduledExecutorService, ThreadFactory y Callable definidas en este paquete.
ExecutorService proporciona métodos para gestionar la terminación, así como métodos para generar futuros para rastrear el estado de ejecución de una o más tareas asincrónicas. El ExecutorService se puede cerrar, lo que hará que deje de aceptar nuevas tareas. Después del cierre, el ejecutor eventualmente terminará sin tareas ejecutándose o esperando a ser ejecutadas, y no se podrán enviar nuevas tareas.
executorService.execute(new TestRunnable());
1. Crear ExecutorService
Creado mediante el método estático de la clase de herramienta java.util.concurrent.Executors .
Métodos de fábrica y utilidad para las clases Executor, ExecutorService, ScheduledExecutorService, ThreadFactory y Callable definidas en el paquete Executors. newFixedThreadPool(3);
ExecutorService executorService = Executors.newSingleThreadExecutor();
2. Agregue la tarea al hilo para su ejecución
Cuando se agrega la tarea al subproceso Cuando está en el grupo, el grupo de subprocesos crea un subproceso para cada tarea y lo ejecuta automáticamente más adelante.
Tres: cerrar el objeto del servicio de ejecución
executorService.shutdown();
Quinto: obtener el valor de retorno de la ejecución de la tarea
Java 5 Después de eso, las tareas se dividen en dos categorías: clases que implementan la interfaz Runnable y clases que implementan la interfaz Callable. ExecutorService puede ejecutar ambas tareas, pero las tareas ejecutables no devuelven valores, mientras que las tareas invocables sí lo hacen. El método call() de Callable solo puede ser ejecutado por el método (tarea
Interfaz pública invocable
Una tarea que devuelve resultados y puede generar excepciones. El implementador define un método llamado llamada que no toma parámetros.
La interfaz Callable es similar y está diseñada para clases cuyas instancias pueden ser ejecutadas por otro hilo.
Pero Runnable no devuelve resultados y no puede generar excepciones marcadas.
Esta clase contiene métodos de utilidad para convertir otros formularios comunes a la clase Callable.
El método call() en Callable es similar al método run() en Runnable, excepto que el primero tiene un valor de retorno y el segundo no.
Cuando el objeto invocable se pasa al método de envío de ExecutorService, el método de llamada se ejecutará automáticamente en el hilo y devolverá un objeto futuro como resultado.
De manera similar, cuando un objeto Runnable se pasa al método de envío de ExecutorService, el método de ejecución se ejecutará automáticamente en el hilo y devolverá el objeto Future como resultado de la ejecución, pero llamará al método get en el objeto Future. devolverá nulo.
Desafortunadamente, en la documentación de la API de Java, esta parte se presenta de una manera oscura, probablemente porque los traductores aún no lo han descubierto. O tal vez simplemente no esté claro. Aquí hay un ejemplo:
importar java.util.ArrayList;
importar java.util.List;
importar java.util.concurrent.*;
publicclass CallableDemo {
publicstaticvoid main(String[] args) {
ExecutorService executorService = Ejecutores. newCachedThreadPool();
List
/Crea 10 tareas y ejecútalas
para ( int i = 0; i <.10; i++) {
/Utilice ExecutorService para realizar tareas de tipo invocable y guardar los resultados en variables futuras
Future
// Almacenar los resultados de ejecución de la tarea en Lista
resultList.add(future);
}
/Recorrer los resultados de la tarea
for (Future
prueba {
System.out.println (fs. get(); //Imprime los resultados de la tarea. get(); //imprime los resultados de la ejecución de cada hilo (tarea)
} catch (InterruptedException e) {
e. printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} finalmente {
// Inicia un apagado secuencial y ejecuta tareas enviadas previamente, pero no acepta nuevas tareas. Si se ha cerrado, la llamada no tiene otro efecto.
id = id;
}
public String call() lanza una excepción {
System .out.println("El método call() se llamó automáticamente, trabajo!!!" + Thread.currentThread().getName());
// Simular operaciones que consumen mucho tiempo
for (int i = 999999; i > 0; i --) ;
return "El método call() se llamó automáticamente y el resultado de la tarea es: " + id + " " + Thread.currentThread().getName()
<; p> }}
}
Resultados de ejecución:
El método call() se llama automáticamente, ¡¡¡funciona!!! pool-1 -thread-1
El método call() se llama automáticamente, ¡¡¡funciona!!! Pool-1-thread-3
El método call() se llama automáticamente, ¡¡¡Funciona!!! Pool-1-Thread-4
El método call() se llama automáticamente, ¡¡¡funciona!!! Se llama automáticamente, ¡trabaja! !!! Pool-1-Thread-2
Llama automáticamente al método call(), ¡¡¡funciona!!! , tarea El resultado es: 0 Pool-1-Thread-1
El método call() se llama automáticamente. El resultado de la tarea es: 1 Pool-1-Thread-2
. El método call() se llama automáticamente, ¡funciona! Pool-1-Thread-2
Llama automáticamente al método call(), ¡funciona! Pool-1-Thread-6
El método call() se llama automáticamente y ¡funciona! ! ! Pool-1-Thread-4
El método call() se llama automáticamente y el resultado de la tarea es: 2 Pool-1-Thread-3
El método call() es se llama automáticamente y el trabajo !!!! El método pool-1-thread-3
call() se llama automáticamente. El resultado de la tarea es: 3. Pool-1-thread-4
call() se llama automáticamente. ), el resultado de la tarea es: 4 El método pool-1-thread-5
call() se llama automáticamente, el resultado de la tarea es: 8 pool. -1-thread-4
El método call () se llama automáticamente y el resultado de la tarea es: 9 pool-1-thread-3
Varios objetos diferentes del grupo de subprocesos ExecutorService p>
1. newCachedThreadPool(): grupo de tipo caché, primero verifique si hay un subproceso previamente establecido en el grupo y, de ser así, reutilícelo. De lo contrario, cree un nuevo hilo y agréguelo al grupo
: el grupo de caché generalmente se usa para realizar algunas tareas asincrónicas con vidas cortas
Por lo tanto, en algunos demonios orientados a la conexión procesos El tipo SERVER no se utiliza mucho.
Los subprocesos reutilizables deben ingresar al grupo dentro del tiempo de espera IDLE (el tiempo de espera predeterminado es 60 segundos). Después de exceder el IDLE, la instancia del subproceso finalizará y se eliminará del grupo.
Tenga en cuenta que los subprocesos colocados en CachedThreadPool no tienen que preocuparse por finalizar; finalizarán automáticamente si permanecen inactivos durante más tiempo que el TIEMPO DE ESPERA.
2. newFixedThreadPool: newFixedThreadPool es casi lo mismo que cacheThreadPool y se puede reutilizar, pero no se pueden crear nuevos subprocesos en ningún momento
: su característica única es: en cualquier momento. , puede haber como máximo un número fijo de subprocesos activos. Si desea crear un nuevo subproceso, solo puede colocarlo en otra cola y esperar a que uno de los subprocesos actuales finalice y se retire del grupo.
-A diferencia de cacheThreadPool, FixThreadPool no tiene un Mecanismo IDLE (puede haberlo, pero debido a que no se menciona en el documento, no lo hay), pero debido a que no se menciona en el documento, debe ser un mecanismo muy largo, que depende del mecanismo IDLE TCP o UDP superior o Mecanismo similar), por lo que FixThreadPool no tiene un mecanismo IDLE, por lo que usarlo No es una buena idea.
mecanismo y similares), por lo que FixThreadPool se usa principalmente para algunos subprocesos concurrentes convencionales muy estables y fijos, que se usan principalmente en servidores
-Desde el código fuente de este método, el grupo de caché y el grupo fijo parecen llamar Es el mismo grupo subyacente, pero los parámetros son diferentes:
El número de subprocesos en el grupo fijo es fijo y está inactivo durante 0 segundos (sin IDLE)
El número de subprocesos en el grupo de caché admite 0 -Integer.MAX_VALUE (obviamente sin considerar la capacidad de recursos del host), 60 segundos IDLE
3.ScheduledThreadPool - grupo de subprocesos planificado
-Threads en este grupo se puede retrasar en secuencia de acuerdo con el plan Ejecución o ejecución en bucle
4.SingleThreadExecutor: una instancia de un solo subproceso, solo hay un subproceso en el grupo en cualquier momento
-usa el mismo grupo subyacente que el grupo de caché y el grupo fijo, pero el número de subprocesos es de 1 a 1,0 segundos IDLE (sin IDLE)
Los cuatro grupos de subprocesos anteriores utilizan la fábrica de subprocesos predeterminada de Executor para crear subprocesos, o puede definir su propia fábrica de subprocesos por separado
El siguiente es el código de fábrica de subprocesos predeterminado:
clase estática DefaultThreadFactory implementa ThreadFactory {
static final AtomicInteger poolNumber = new AtomicInteger(1);
grupo final ThreadGroup;
final AtomicInteger threadNumber = nuevo AtomicInteger(1);
final String namePrefix ;
DefaultThreadFactory() {
SecurityManager s = System. GetSecurityManager()getSecurityManager();
grupo = (s !) s.getThreadGroup = (s !) s.getThreadGroup() :Thread.currentThread().getThreadGroup();
namePrefix = "pool-" + poolNumber.getAndAndPrefix.getAndPrefix.getAndPrefix.getAndPrefix.getAndPrefix.getAndPrefix.getAndPrefix.getAndPrefix+ poolNumber.getAndIncrement () + "-thread-";
}
Hilo público newThread( Runnable r) {
Hilo t = nuevo hilo(group, r,namePrefix + threadNumber.getAndIncrement (),0);
if (t.isDaemon())
t.setDaemon(false);
if (t.getPriority() ! = Thread.NORM_PRIORITY)
t.setPriority(Thread.NORM_PRIORITY);
Devuelve t;
}
}
También puedes definir tu propio ThreadFactory y agregarlo a los parámetros del grupo de compilación
public static ExecutorS
servicio newCachedThreadPool(ThreadFactory threadFactory) {
Método Execute() del Ejecutor
El método Execute() agrega la instancia Runnable al grupo y realiza algunos cálculos del tamaño del grupo y configuraciones de prioridad
El método ejecutar() en sí está definido en la interfaz Executor, y existen múltiples clases de implementación que definen diferentes métodos ejecutar()
Por ejemplo, por ejemplo, la clase ThreadPoolExecutor (caché, fija, single) (todos los grupos lo llaman) el método de ejecución es el siguiente:
public void ejecutar(comando ejecutable) {
if (comando == null)
throw new NullPointerException();
if (poolSize >= corePoolSize ||! addIfUnderCorePoolSize(command)) {
if (runState == RUNNING && ; workQueue.offer(command )) {
if (runState != RUNNING || poolSize == 0)
asegurarQueuedTaskHandled(comando);
}
else if (! addIfUnderMaximumPoolSize(command))
rechazar(command); // está apagado o saturado
}
}
}