hilos - scheduledexecutorservice java 8
¿Un ExecutorService obtiene basura cuando está fuera de alcance? (2)
Estoy haciendo esta pregunta porque estoy creando una gran cantidad de servicios de ejecutor y, si bien es posible que ya tenga una pérdida de memoria en algún lugar que deba investigarse, creo que un cambio reciente en el siguiente código la empeoró, por lo que estoy tratando de confirmar Que esta pasando:
@FunctionalInterface
public interface BaseConsumer extends Consumer<Path> {
@Override
default void accept(final Path path) {
String name = path.getFileName().toString();
ExecutorService service = Executors.newSingleThreadExecutor(runnable -> {
Thread thread = new Thread(runnable, "documentId=" + name);
thread.setDaemon(true);
return thread;
});
Future<?> future = service.submit(() -> {
baseAccept(path);
return null;
});
try {
future.get();
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
} catch (ExecutionException ex) {
throw new RuntimeException(ex);
}
}
void baseAccept(final Path path) throws Exception;
}
Entonces a esta Consumer<Path>
se la llama en otro grupo de subprocesos con (normalmente) N = 2 subprocesos, no estoy seguro de si eso es relevante.
La pregunta es: ¿el ExecutorService service
queda fuera del alcance y se recolecta la basura una vez que ha finalizado la BaseConsumer#accept
?
¿El servicio ExecutorService
BaseConsumer.accept()
fuera del alcance y se recolecta la basura una vez queBaseConsumer.accept()
ha finalizado?
Sí.
De hecho, el grupo de subprocesos asociado también se debe recolectar basura ... eventualmente.
El ExecutorService
que es creado por Executors.newSingleThreadExecutor()
una instancia de FinalizableDelegatedExecutorService
. Esa clase tiene el método finalize()
que llama a shutdown()
en el objeto ExecutorService
envuelto. Siempre que todas las tareas pendientes realmente terminen, el objeto de servicio cerrará su grupo de subprocesos.
(AFAIK, esto no está especificado. Pero es lo que se implementa de acuerdo con el código fuente, en Java 6 en adelante.)
¿Se agrega un finally {service.shutdown (); } en el try-catch de future.get () ayuda a recuperar recursos más rápido? (No necesariamente recolección de basura el objeto de servicio).
Si lo hace Al llamar a shutdown()
, los subprocesos se liberan tan pronto como se completan las tareas pendientes. El procedimiento se inicia de inmediato, mientras que si lo dejas en manos del recolector de basura, no se iniciará hasta que se llame al finalizador.
Ahora, si los recursos fueran solo objetos Java "ordinarios", esto no importaría. Pero en este caso, el recurso que está reclamando es un subproceso de Java y que tiene recursos del sistema operativo asociados (por ejemplo, un subproceso nativo) y una porción no trivial de memoria de fuera del montón. Así que tal vez valga la pena hacer esto.
Pero si está buscando optimizar esto, tal vez debería crear un objeto ExecutorService
larga duración y compartirlo en múltiples instancias de "consumidor".
Quiero que la ejecución tenga lugar en un subproceso con nombre, tiene que ver con que sea más fácil de registrar. En cualquier caso, este código debería funcionar.
Puedes hacer esto mucho más simple / rápido
Thread t = Thread.currentThread();
String name = t.getName();
try {
t.setName("My new thread name for this task");
// do task
} finally {
t.setName(name);
}
De esta manera puede usar un hilo con nombre sin crear uno nuevo.