私は正常に終了するために、シャットダウンフックを作成するために、いくつかのJavaコードを持っている場合+ C、Ctrlクライアントプレス:
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);
}
私は、コマンドラインからこれを実行すると、それは(コマンドプロンプトにほとんどすぐにメインスレッドが終了してリターン)期待通りに動作します。しかし、私はこれは、次のC ++のコードを代わりに使用して呼び出すJNIラッパーを書いた場合:
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();
その後、shutdownHandler
30秒のタイムアウトが経過するまでメソッドがハングは、次いで、C ++コードと、最終的に出口に制御を返します。できるようにする方法のいずれかを知っているshutdownHandler
JNI呼び出しから起動したときにメソッドがメインスレッドに参加するには?
あなたの最初の例では、メインスレッドが終了し、JVMには非デーモンスレッドが出て、JVMのシャットダウンを開始しますが存在しないことを検出します。それも、シャットダウン前に終了したように、この時点では、メインスレッドへの参加は問題ないが、。
あなたの第二の変形、メインスレッドでは、実行スレッドすなわちmain
経由する方法をenv -> CallStaticVoidMethod(…)
、実行忙しいですjvm -> DestroyJavaVM()
。その関数は、このスレッドの完了のためのシャットダウンハンドラとあなたのシャットダウンハンドラ待ちの完了を待っているので、あなたはデッドロックを持っています。
あなたも、純粋なJavaコードと同様の動作を得ることができます。あなたが置いたときSystem.exit(0);
の最後にmain
メインスレッドをさせる、方法その完了のためのシャットダウンや待機を開始するには、同様のデッドロックを取得します。
一般的に、あなたは実行しないでくださいjoin
シャットダウンハンドラの動作を。これらのハンドラは、クリーンアップし、可能な限り迅速に返すことになっています。
または、としてドキュメントがそれを置きます:
シャットダウンフックは仮想マシンのライフサイクルの微妙な時期に起動、したがって、防御的にコード化されなければなりません。これらは、特に、スレッドセーフであることを、可能な限りにおいてデッドロックを回避するために記述する必要があります。彼らはまた、シャットダウンの過程で自分自身を自分自身のシャットダウンフックを登録し、そのためかもしれないしている可能性があり、サービス時に盲目的に頼るべきではありません。そのようなAWTイベントディスパッチスレッドのような他のスレッドベースのサービスを使用する試みは、例えば、デッドロックにつながる可能性があります。