¿Ejemplo útil de un gancho de cierre en Java?
synchronized class in java (2)
Estoy tratando de asegurarme de que mi aplicación Java tome medidas razonables para ser robusta, y parte de eso implica cerrar con gracia. Estoy leyendo sobre los ganchos de cierre y realmente no entiendo cómo usarlos en la práctica.
¿Hay algún ejemplo práctico por ahí?
Digamos que tenía una aplicación muy simple como esta a continuación, que escribe números en un archivo, 10 en una línea, en lotes de 100, y quiero asegurarme de que un lote determinado termine si el programa se interrumpe. Obtuve cómo registrar un enlace de cierre, pero no tengo idea de cómo integrar eso en mi aplicación. ¿Alguna sugerencia?
package com.example.test.concurrency;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintWriter;
public class GracefulShutdownTest1 {
final private int N;
final private File f;
public GracefulShutdownTest1(File f, int N) { this.f=f; this.N = N; }
public void run()
{
PrintWriter pw = null;
try {
FileOutputStream fos = new FileOutputStream(this.f);
pw = new PrintWriter(fos);
for (int i = 0; i < N; ++i)
writeBatch(pw, i);
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
finally
{
pw.close();
}
}
private void writeBatch(PrintWriter pw, int i) {
for (int j = 0; j < 100; ++j)
{
int k = i*100+j;
pw.write(Integer.toString(k));
if ((j+1)%10 == 0)
pw.write(''/n'');
else
pw.write('' '');
}
}
static public void main(String[] args)
{
if (args.length < 2)
{
System.out.println("args = [file] [N] "
+"where file = output filename, N=batch count");
}
else
{
new GracefulShutdownTest1(
new File(args[0]),
Integer.parseInt(args[1])
).run();
}
}
}
Los ganchos de cierre son hilos no iniciados que están registrados con Runtime.addShutdownHook (). JVM no ofrece ninguna garantía sobre el orden en que se inician los ganchos de cierre. Para obtener más información, consulte http://techno-terminal.blogspot.in/2015/08/shutdown-hooks.html
Usted podría hacer lo siguiente:
- Deje que el gancho de cierre configure AtomicBoolean (o boolean volátil) "keepRunning" como falso
- (Opcionalmente,
.interrupt
los hilos de trabajo si esperan datos en alguna llamada de bloqueo) - Espere a que los hilos de trabajo (ejecutando
writeBatch
en su caso) finalicen, llamando al métodoThread.join()
en los hilos de trabajo. - Terminar el programa
Un código incompleto:
- Agregue un
static volatile boolean keepRunning = true;
En run () cambias a
for (int i = 0; i < N && keepRunning; ++i) writeBatch(pw, i);
En main () agrega:
final Thread mainThread = Thread.currentThread(); Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { keepRunning = false; mainThread.join(); } });
Eso es más o menos cómo hago un elegante "rechazar a todos los clientes al presionar Control-C" en la terminal.
De los documentos :
Cuando la máquina virtual comienza su secuencia de apagado, iniciará todos los enganches de apagado registrados en algún orden no especificado y los dejará funcionar al mismo tiempo. Cuando todos los enganches hayan finalizado, se ejecutarán todos los finalizadores no invocados si se ha habilitado la finalización a la salida. Finalmente, la máquina virtual se detendrá.
Es decir, un gancho de cierre mantiene la JVM en ejecución hasta que el enlace finalice (devuelto desde el método run () .