tutorialspoint threads thread que multithread multi manage implement example java multithreading

threads - runnable java



Agraciado cierre de hilos y ejecutor (5)

El siguiente fragmento de código intenta completar esto.

El código se repite para siempre y verifica si hay solicitudes pendientes para procesar. Si hay alguno, crea un nuevo hilo para procesar la solicitud y lo envía al ejecutor. Una vez que todos los hilos están listos, duerme durante 60 segundos y nuevamente verifica las solicitudes pendientes.

public static void main(String a[]){ //variables init code omitted ExecutorService service = Executors.newFixedThreadPool(15); ExecutorCompletionService<Long> comp = new ExecutorCompletionService<Long>(service); while(true){ List<AppRequest> pending = service.findPendingRequests(); int noPending = pending.size(); if (noPending > 0) { for (AppRequest req : pending) { Callable<Long> worker = new RequestThread(something, req); comp.submit(worker); } } for (int i = 0; i < noPending; i++) { try { Future<Long> f = comp.take(); long name; try { name = f.get(); LOGGER.debug(name + " got completed"); } catch (ExecutionException e) { LOGGER.error(e.toString()); } } catch (InterruptedException e) { LOGGER.error(e.toString()); } } TimeUnit.SECONDS.sleep(60); } }

Mi pregunta es que la mayoría del procesamiento realizado por estos hilos trata con la base de datos. Y este programa se ejecutará en una máquina de Windows. ¿Qué sucede con estos hilos cuando alguien intenta cerrar o cerrar sesión en la máquina? Cómo cerrar con gracia los hilos en ejecución y también el ejecutor.



El libro " Concurrencia de Java en la práctica " afirma:

7.4. Cierre de JVM

La JVM puede cerrarse de manera ordenada o abrupta. Un cierre ordenado se inicia cuando finaliza el último subproceso "normal" (no demoníaco), alguien llama a System.exit o por otros medios específicos de plataforma (como enviar un SIGINT o presionar Ctrl-C). [...]

7.4.1. Ganchos de cierre

En un cierre ordenado, la JVM primero inicia todos los ganchos de apagado registrados. Los ganchos de cierre son hilos no iniciados que están registrados con Runtime.addShutdownHook. La JVM no garantiza el orden en que se inician los ganchos de desconexión. Si alguno de los subprocesos de aplicación (daemon o no demonio) aún se está ejecutando en el momento del cierre, continúan ejecutándose al mismo tiempo que el proceso de apagado. Cuando se hayan completado todos los enganches de cierre, la JVM puede elegir ejecutar los finalizadores si runFinalizersOnExit es verdadero, y luego se detiene. La JVM no intenta detener o interrumpir ningún subproceso de aplicación que aún se esté ejecutando en el momento del cierre; se terminan abruptamente cuando la JVM finalmente se detiene. Si los ganchos de cierre o finalizadores no se completan, entonces el proceso de apagado ordenado "se bloquea" y la JVM debe cerrarse abruptamente. [...]

Los bits importantes son: "La JVM no intenta detener o interrumpir los subprocesos de aplicaciones que todavía se ejecutan en el momento del cierre, sino que se interrumpen abruptamente cuando la JVM finalmente se detiene". así que supongo que la conexión con el DB terminará abruptamente, si no hay ganchos de cierre para hacer una limpieza elegante (si está utilizando frameworks, generalmente proporcionan tales hooks de apagado). En mi experiencia, la sesión en la base de datos puede permanecer hasta que el DB la agote, cuando la aplicación. se termina sin tales ganchos.


Puede invocar shutdown() en ExecutorService :

Inicia un cierre ordenado en el que se ejecutan las tareas enviadas anteriormente, pero no se aceptarán nuevas tareas.

o puede llamar a shutdownNow() :

Intenta detener todas las tareas de ejecución activa, detiene el procesamiento de las tareas en espera y devuelve una lista de las tareas que estaban esperando su ejecución.

No hay garantías más allá de los intentos de mejor esfuerzo para detener el procesamiento de tareas de ejecución activa. Por ejemplo, las implementaciones típicas se cancelarán a través de Thread.interrupt (), por lo que cualquier tarea que no responda a las interrupciones puede que nunca termine.

A cuál de ustedes llame depende de cuánto lo quieran detener ...


Tuve un problema similar, utilizo para obtener un error como

oacloader.WebappClassLoaderBase :: La aplicación web [ROOT] parece haber iniciado un hilo llamado [pool-2-thread-1] pero no ha podido detenerlo. Esto es muy probable que cree una pérdida de memoria. Stack trace of thread: sun.misc.Unsafe.park (Método nativo) java.util.concurrent.locks.LockSupport.park (LockSupport.java:175) java.util.concurrent.locks.AbstractQueuedSynchronizer $ ConditionObject.await (AbstractQueuedSynchronizer. java: 2039)

El código de Bellow lo arregló

private ThreadPoolExecutor executorPool; @PostConstruct public void init() { log.debug("Initializing ThreadPoolExecutor"); executorPool = new ThreadPoolExecutor(1, 3, 1, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(1)); } @PreDestroy public void destroy() { log.debug("Shuting down ThreadPoolExecutor"); executorPool.shutdown(); }


Un cierre ordenado típico de un ExecutorService podría verse más o menos así:

final ExecutorService executor; Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { executor.shutdown(); if (!executor.awaitTermination(SHUTDOWN_TIME)) { //optional * Logger.log("Executor did not terminate in the specified time."); //optional * List<Runnable> droppedTasks = executor.shutdownNow(); //optional ** Logger.log("Executor was abruptly shut down. " + droppedTasks.size() + " tasks will not be executed."); //optional ** } } });

* Puede registrar que el ejecutor todavía tenía tareas para procesar después de esperar el tiempo que estaba dispuesto a esperar.
** Puede intentar forzar a los Threads de los trabajadores del ejecutor a abandonar sus tareas actuales y asegurarse de que no inicien ninguno de los restantes.

Tenga en cuenta que la solución anterior funcionará cuando un usuario emita una interrupción en su proceso java o cuando su ExecutorService solo contenga hilos daemon. Si, en cambio, el ExecutorService contiene subprocesos no-daemon que no se han completado, la JVM no intentará apagarse y, por lo tanto, no se invocarán los ganchos de cierre.

Si intenta cerrar un proceso como parte de un ciclo de vida de aplicación discreto (no un servicio), entonces el código de apagado no se debe colocar dentro de un enlace de cierre sino en la ubicación adecuada donde el programa está diseñado para finalizar.