Estuve leyendo bastante sobre esto en las últimas horas, y simplemente no veo ninguna razón (razón válida ) para llamar shutdown()
a ExecutorService
, a menos que tengamos una aplicación enorme que almacene, docenas y docenas de diferentes servicios ejecutores que no se utilizan para mucho tiempo.
Lo único que hace (por lo que he recopilado) que hace el apagado es hacer lo que hace un hilo normal una vez que está hecho. Cuando el hilo normal termine el método de ejecución de Runnable (o invocable), se pasará a Garbage Collection para su recolección. Con Executor Service, los subprocesos simplemente se pondrán en espera, no se marcarán para la recolección de basura. Para eso se necesita el apagado.
Ok, volvamos a mi pregunta. ¿Hay alguna razón para llamar al apagado con ExecutorService
mucha frecuencia, o incluso justo después de enviarle algunas tareas? Me gustaría dejar atrás el caso de que alguien lo está haciendo y, inmediatamente después, llama a awaitTermination()
cuando se valida. Una vez que hacemos eso, tenemos que volver a crear uno nuevo ExecutorService
, para hacer lo mismo. ¿No es la idea general ExecutorService
reutilizar los hilos? Entonces, ¿por qué destruir el ExecutorService
tan pronto?
¿No es una forma racional de simplemente crear ExecutorService
(o acoplar dependiendo de cuántos necesite), luego, durante la ejecución de la aplicación, pasarles las tareas una vez que aparezcan, y luego, en la salida de la aplicación o en algunas otras etapas importantes, apague esos ejecutores? ?
Me gustaría recibir la respuesta de algunos codificadores experimentados que escriben mucho código asincrónico usando ExecutorServices.
Segunda pregunta lateral, acuerdos un poco más pequeños con la plataforma Android. SI algunos de ustedes dirán que no es la mejor idea apagar los ejecutores cada vez, y programan en Android, ¿podrían decirme cómo manejan esos cierres (para ser específicos, cuando los ejecutan) cuando nos ocupamos de diferentes eventos de ciclo de vida de la aplicación.
Debido al comentario de CommonsWare, hice la publicación neutral. Realmente no estoy interesado en discutir sobre eso a muerte y parece que está conduciendo allí. Solo me interesa conocer lo que pregunté aquí a desarrolladores experimentados, si están dispuestos a compartir sus experiencias. Gracias.
fuente
Respuestas:
El
shutdown()
método hace una cosa: evita que los clientes envíen más trabajo al servicio ejecutor. Esto significa que todas las tareas existentes aún se ejecutarán hasta su finalización a menos que se tomen otras acciones. Esto es cierto incluso para las tareas programadas, por ejemplo, para un ScheduledExecutorService: las nuevas instancias de la tarea programada no se ejecutarán. Esto puede resultar útil en varios escenarios.Supongamos que tiene una aplicación de consola que tiene un servicio ejecutor que ejecuta N tareas. Si el usuario presiona CTRL-C, espera que la aplicación finalice, posiblemente sin problemas. ¿Qué significa con gracia? Tal vez desee que su aplicación no pueda enviar más tareas al servicio ejecutor y, al mismo tiempo, desee esperar a que se completen sus N tareas existentes. Puede lograr esto usando un gancho de apagado como último recurso:
final ExecutorService service = ... // get it somewhere Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { @Override public void run() { System.out.println("Performing some shutdown cleanup..."); service.shutdown(); while (true) { try { System.out.println("Waiting for the service to terminate..."); if (service.awaitTermination(5, TimeUnit.SECONDS)) { break; } } catch (InterruptedException e) { } } System.out.println("Done cleaning"); } }));
Este enlace cerrará el servicio, lo que evitará que su aplicación envíe nuevas tareas y esperará a que se completen todas las tareas existentes antes de cerrar la JVM. La terminación en espera se bloqueará durante 5 segundos y volverá a ser verdadera si se cierra el servicio. Esto se hace en un bucle para que esté seguro de que el servicio se cerrará eventualmente. La InterruptedException se traga cada vez. Esta es la mejor manera de cerrar un servicio ejecutor que se reutiliza en toda su aplicación.
Este código no es perfecto. A menos que esté absolutamente seguro de que sus tareas terminarán eventualmente, es posible que desee esperar un tiempo de espera determinado y luego simplemente salir, abandonando los subprocesos en ejecución. En este caso, tendría sentido llamar también
shutdownNow()
después del tiempo de espera en un intento final de interrumpir los subprocesos en ejecución (shutdownNow()
también le dará una lista de tareas esperando para ejecutarse). Si sus tareas están diseñadas para responder a una interrupción, esto funcionará bien.Otro escenario interesante es cuando tienes un ScheduledExecutorService que realiza una tarea periódica. La única forma de detener la cadena de tareas periódicas es llamar
shutdown()
.EDITAR: Me gustaría agregar que no recomendaría usar un gancho de apagado como se muestra arriba en el caso general: puede ser propenso a errores y debería ser solo un último recurso. Además, si tiene muchos enlaces de cierre registrados, el orden en el que se ejecutarán no está definido, lo que podría no ser deseable. Yo prefiero tener la aplicación explícita llamar
shutdown()
aInterruptedException
.fuente
shutdown()
para no desperdiciar recursos cuando sea innecesario. Si la aplicación se cierra, los subprocesos en el grupo eventualmente serán recolectados como basura (después de que estén inactivos durante 60 segundos de manera predeterminada). Tenga en cuenta que si desea que el grupo esté delimitado o desea una vida útil diferente del hilo, puede crearThreadPoolExecutor
directamente un archivo.Si. No debe destruir y volver a crear con
ExecutorService
frecuencia. InicialiceExecutorService
cuando lo necesite (principalmente al inicio) y manténgalo activo hasta que haya terminado.Si. Es racional cerrar
ExecutorService
en etapas importantes como la salida de la aplicación, etc.Suponga que
ExecutorService
se comparte entre diferentes actividades en su aplicación. Cada actividad se pausará / reanudará en diferentes intervalos de tiempo y aún necesitará unaExecutorService
para su aplicación.En lugar de administrar el estado de los
ExecutorService
métodos del ciclo de vida de la actividad, mueva la administración de ExecutorService (Creación / Apagado) a su Servicio personalizado .Crear
ExecutorService
en servicio =>onCreate()
y apagarlo correctamente enonDestroy()
Forma recomendada de apagar
ExecutorService
:Cómo apagar correctamente Java ExecutorService
fuente
Libro de referencia
Chaper: 14 Página: 814
fuente
Razón para llamar a shutdown () en ExecutorService
Hoy me encontré con una situación en la que tengo que esperar hasta que una máquina esté lista, antes de comenzar una serie de tareas en esa máquina.
Hago una llamada REST a esta máquina, si no recibo 503 (Servidor no disponible), la máquina está lista para procesar mis solicitudes. Entonces, espero hasta obtener 200 (éxito) para la primera llamada de REST.
Hay varias formas de lograrlo, utilicé ExecutorService para crear un hilo y lo programé para que se ejecute después de cada X segundos. Entonces, necesito detener este hilo con una condición, mira esto ...
final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); Runnable task = () -> { try { int statusCode = restHelper.firstRESTCall(); if (statusCode == 200) { executor.shutdown(); } } catch (Exception e) { e.printStackTrace(); } }; int retryAfter = 60; executor.scheduleAtFixedRate(task, 0, retryAfter, TimeUnit.SECONDS);
Segunda pregunta lateral, acuerdos un poco más pequeños con la plataforma Android.
¡Quizás pueda responder si me proporciona un poco más de contexto! Además, según mi experiencia con el desarrollo de Android, rara vez necesitas Threads. ¿Estás desarrollando un juego o una aplicación que necesita hilos para funcionar? Si no es así, en Android tienes otras formas de abordar problemas como el escenario que expliqué anteriormente. Puede utilizar TimerTask, AsyncTask o Handlers o Loaders según el contexto. Esto se debe a que si UIThread espera mucho tiempo, sabes lo que sucede: /
fuente
Esto es genuino a pesar de las empresas planificadas, por ejemplo, para un ScheduledExecutorService: los nuevos casos de la asignación reservada no se ejecutarán.
Deberíamos esperar que tenga una aplicación cómoda que tenga una administración de agentes que ejecute N recados.
¿No estoy captando su significado sin esfuerzo? Tal vez necesite que su solicitud no tenga la opción de enviar más asignaciones a la administración del agente y, mientras tanto, debe esperar a que finalicen sus N compromisos actuales.
Excepto si estás totalmente seguro de que tus recados terminarán al final, deberías estar sentado durante un descanso determinado y luego simplemente salir, abandonando los hilos de ejecución.
En el caso de que sus actividades estén destinadas a reaccionar a interferencias, esto funcionará bien.
Otra situación intrigante es el punto en el que tiene un ScheduledExecutorService que realiza una actividad.
La mejor forma de detener la cadena de actividad es llamar a shutdown ()
fuente