Tengo algo de código Java para crear un gancho de cierre con el fin de salir limpiamente cuando las prensas cliente Ctrl + C:
private static void shutdownHandler(Thread mainThread) {
try {
mainThread.join(30000);
} catch (InterruptedException e) {
}
}
public static void main(String[] args) {
final Thread mainThread = Thread.currentThread();
Thread shutdownThread = new Thread(() -> shutdownHandler(mainThread));
Runtime.getRuntime().addShutdownHook(shutdownThread);
}
Cuando ejecuto esto desde la línea de comandos, funciona como se esperaba (las principales salidas de hilo y vuelve casi inmediatamente a la línea de comandos). Sin embargo, si escribo un envoltorio de JNI que llama a este mediante el siguiente código C ++ en su lugar:
JavaVMInitArgs vm_args;
// Populate vm_args
JavaVM *jvm;
JNIEnv *env;
JNI_CreateJavaVM(&jvm, reinterpret_cast<void**>(&env), &vm_args);
jclass mainClass = env->FindClass("path/to/my/class");
jmethod mainMethod = env->GetStaticMethodID(mainClass, "main", "([L" STRING_CLASS ";)V");
jclass stringClass = env->FindClass(STRING_CLASS);
jobjectArray mainArgs = env->NewObjectArray(0, stringClass, NULL);
env->CallStaticVoidMethod(mainClass, mainMethod, mainArgs);
jvm->DestroyJavaVM();
A continuación, los shutdownHandler
cuelga método hasta los 30 transcurre segundo de tiempo de espera, a continuación, devuelve el control al código C ++ y eventualmente salidas. ¿Alguien sabe de una manera de permitir que el shutdownHandler
método para unir el hilo principal cuando se arranca desde una llamada JNI?
En el primer ejemplo, las principales salidas de rosca, a continuación, la JVM detecta que no hay hilos no Daemon derecho e iniciará el cierre de JVM. En este momento, no hay ningún problema de unirse al hilo principal, ya que ha terminado incluso antes de la desconexión.
En su segunda variante, el hilo principal, es decir, el hilo que ejecuta el main
método a través env -> CallStaticVoidMethod(…)
, es ocupado ejecutando jvm -> DestroyJavaVM()
. Dado que la función de espera para la realización de los manipuladores de apagado y que espera el controlador de parada para la realización de este hilo, que tiene un punto muerto.
Usted puede obtener un comportamiento similar con código Java puro también. Cuando se coloca System.exit(0);
al final del main
método, dejando que el hilo principal iniciar el apagado y esperar a su finalización, se obtiene un punto muerto similar.
En general, no debe realizar join
la operación en los manejadores de apagado. Estos controladores se supone que limpiar y volver lo más rápido posible.
O, como los de documentación pone:
ganchos de apagado se ejecutan en un momento delicado en el ciclo de vida de una máquina virtual y, por tanto, deben codificarse defensiva. Deben, en particular, pueden escribir a ser flujos seguros y evitar los puntos muertos en la medida de lo posible. Asimismo, no deben confiar ciegamente en los servicios que pueden haber registrado sus propios ganchos de cierre y por lo tanto pueden por sí mismos en el proceso de apagado. Los intentos de utilizar otros servicios basados en hilo como el hilo de eventos AWT-expedición, por ejemplo, puede conducir a puntos muertos.