やりたいこと
JavaプログラムでaddShutdownHookに指定したThreadがどのシグナルで終了したときに呼び出されるのかを確認する。
Runtime (Java Platform SE 8)
確認方法
- 以下のJavaプログラムを実行する
- 起動したプログラムにkillコマンドでシグナルを投げて「call shutdown hook」が標準出力に出るか確認する。
public class SignalTest {
public static void main(String [] args) {
Runtime.getRuntime().addShutdownHook(new Thread(
() -> System.out.println("call shutdown hook")
));
while(true) {
try {
Thread.sleep(5000);
System.out.println("exec...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
確認対象のシグナルは以下の4つ
- SIGINT(2)
- SIGQUIT(3)
- SIGTERM(15)
- SIGKILL(9)
確認環境
- OS
- Kernel
- javac
- java
- openjdk version "1.8.0_162"
- OpenJDK Runtime Environment (build 1.8.0_162-8u162-b12-0ubuntu0.16.04.2-b12)
- OpenJDK 64-Bit Server VM (build 25.162-b12, mixed mode)
確認結果
SIGINT(2)
呼び出された。
$ java SignalTest
exec...
call shutdown hook
$ kill -2 pid
SIGQUIT(3)
呼び出されない。
Javadumpが出力され、処理が継続している。
$ java SignalTest
exec...
exec...
exec...
exec...
exec...
2018-04-08 10:35:05
Full thread dump OpenJDK 64-Bit Server VM (25.162-b12 mixed mode):
"Service Thread" #9 daemon prio=9 os_prio=0 tid=0x00007f2b580c8000 nid=0x81e runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C1 CompilerThread3" #8 daemon prio=9 os_prio=0 tid=0x00007f2b580c3800 nid=0x81d waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread2" #7 daemon prio=9 os_prio=0 tid=0x00007f2b580bf000 nid=0x81c waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread1" #6 daemon prio=9 os_prio=0 tid=0x00007f2b580bd000 nid=0x81b waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread0" #5 daemon prio=9 os_prio=0 tid=0x00007f2b580ba000 nid=0x81a waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Signal Dispatcher" #4 daemon prio=9 os_prio=0 tid=0x00007f2b580b8000 nid=0x819 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Finalizer" #3 daemon prio=8 os_prio=0 tid=0x00007f2b58090800 nid=0x818 in Object.wait() [0x00007f2b1f0ce000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x000000071a208ec0> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
- locked <0x000000071a208ec0> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:212)
"Reference Handler" #2 daemon prio=10 os_prio=0 tid=0x00007f2b5808c000 nid=0x817 in Object.wait() [0x00007f2b1f1cf000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x000000071a206b68> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:502)
at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
- locked <0x000000071a206b68> (a java.lang.ref.Reference$Lock)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)
"main" #1 prio=5 os_prio=0 tid=0x00007f2b5800a800 nid=0x80b waiting on condition [0x00007f2b5fe1e000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at SignalTest.main(SignalTest.java:10)
"VM Thread" os_prio=0 tid=0x00007f2b58084000 nid=0x816 runnable
"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00007f2b5801f800 nid=0x80c runnable
"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x00007f2b58021800 nid=0x80d runnable
"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x00007f2b58023000 nid=0x80e runnable
"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x00007f2b58025000 nid=0x80f runnable
"GC task thread#4 (ParallelGC)" os_prio=0 tid=0x00007f2b58026800 nid=0x810 runnable
"GC task thread#5 (ParallelGC)" os_prio=0 tid=0x00007f2b58028800 nid=0x811 runnable
"GC task thread#6 (ParallelGC)" os_prio=0 tid=0x00007f2b5802a000 nid=0x812 runnable
"GC task thread#7 (ParallelGC)" os_prio=0 tid=0x00007f2b5802c000 nid=0x813 runnable
"GC task thread#8 (ParallelGC)" os_prio=0 tid=0x00007f2b5802d800 nid=0x814 runnable
"GC task thread#9 (ParallelGC)" os_prio=0 tid=0x00007f2b5802f000 nid=0x815 runnable
"VM Periodic Task Thread" os_prio=0 tid=0x00007f2b580ca800 nid=0x81f waiting on condition
JNI global references: 309
Heap
PSYoungGen total 148992K, used 7680K [0x000000071a200000, 0x0000000724800000, 0x00000007c0000000)
eden space 128000K, 6% used [0x000000071a200000,0x000000071a980098,0x0000000721f00000)
from space 20992K, 0% used [0x0000000723380000,0x0000000723380000,0x0000000724800000)
to space 20992K, 0% used [0x0000000721f00000,0x0000000721f00000,0x0000000723380000)
ParOldGen total 339968K, used 0K [0x00000005ce600000, 0x00000005e3200000, 0x000000071a200000)
object space 339968K, 0% used [0x00000005ce600000,0x00000005ce600000,0x00000005e3200000)
Metaspace used 3490K, capacity 4632K, committed 4864K, reserved 1056768K
class space used 380K, capacity 459K, committed 512K, reserved 1048576K
exec...
exec...
$ kill -3 pid
SIGTERM(15)
呼び出された。
$ java SignalTest
exec...
exec...
exec...
call shutdown hook
$ kill -15 pid
SIGKILL(9)
呼び出されない。
最後の「強制終了」はjvmの出力?と思われる。javadocの記述通りの挙動になった。
$ java SignalTest
exec...
exec...
exec...
強制終了
$ kill -9 pid