JVM thread interruption

3
Sadayuki Furuhashi @frsyuki

JVMがSIGTERMを受け取ったときに、そのシグナルがどのスレッドに配送され、どのスレッドが中断されるのか調べているところなのだけども、Javaにシグナルマスクなんてあったかな。

2014-08-05 02:55:10
Sadayuki Furuhashi @frsyuki

実験してみたところ、SIGTERMはshutdown hookの起動にしか使われないらしい。他のスレッドではマスクされているようで、IOもsleepも中断されない。shutdown hookの実行が終了すると、全スレッドが強制的に終了する。finallyも呼ばれない。

2014-08-05 03:07:32
Sadayuki Furuhashi @frsyuki

つまりshutdown hookの中でスレッドの終了を待たないと、プロセスの外部でゴミが残る可能性がある。このときに注意すべきは ExecutorService.shutdownNow で、コレを呼ぶとタスクを実行中のスレッドが中断される。

2014-08-05 03:12:20
Sadayuki Furuhashi @frsyuki

java.io.InterruptedIOExceptionは、どういう条件で起こるんだろう…どうにも再現できないな。

2014-08-05 03:16:42
Sadayuki Furuhashi @frsyuki

read(2)やwrite(2)がEINTRで返った時にjava.io.InterruptedIOExceptionが発生するのは分かるけど、JVMでSIGTERMを使ってどうやって発生させるのか。

2014-08-05 03:23:43
Sadayuki Furuhashi @frsyuki

read(2)やwrite(2)がEINTRで返った時にjava.io.InterruptedIOExceptionが発生するのは分かるけど、JVMでSIGTERMを使ってどうやって発生させるのか。

2014-08-05 03:23:43
Sadayuki Furuhashi @frsyuki

ん、そもそもreadは中断可能なメソッドじゃないのか。これMac OS X上だけ…? Linuxでも試すか。

2014-08-05 03:26:37
Sadayuki Furuhashi @frsyuki

Linuxでも同じだった。少なくともFileInputStream.readは、Thread#interrupt() では中断されない。interruptフラグがセットされた状態でFileInputStream.readを呼んでも、read(2)は通常通り発行される。

2014-08-05 03:28:25
Sadayuki Furuhashi @frsyuki

Linuxでも同じだった。少なくともFileInputStream.readは、Thread#interrupt() では中断されない。interruptフラグがセットされた状態でFileInputStream.readを呼んでも、read(2)は通常通り発行される。

2014-08-05 03:28:25
Sadayuki Furuhashi @frsyuki

つまりは、while(file.read(buffer) >= 0) { … } みたいなスレッドは、Thread.interruptでは中断できない。まじか。

2014-08-05 03:29:21
Sadayuki Furuhashi @frsyuki

ではClosedByInterruptExceptionはどうか。試すか…

2014-08-05 03:31:10
小崎 資広 (KOSAKI Motohiro) @kosaki55tea

@frsyuki 途中までJVMがシグナル受けた時の話だったのに、いきなりJavaからシグナル送る話になってるのはなんで

2014-08-05 03:32:27
Sadayuki Furuhashi @frsyuki

いま考えているのは、Javaでサーバプログラムを書くときに、どうやって終了させるか。SIGTERMを送るのは良いとして、その後でどんな例外をcatchすればいいのか、とかとか。

2014-08-05 03:34:54
Sadayuki Furuhashi @frsyuki

@kosaki55tea ぁーいやいや、SIGTERMを使ってJVMにjava.io.InterruptedIOExceptionを発生させる方法は?という話でした。

2014-08-05 03:35:40
Sadayuki Furuhashi @frsyuki

@kosaki55tea ぁーいやいや、SIGTERMを使ってJVMにjava.io.InterruptedIOExceptionを発生させる方法は?という話でした。

2014-08-05 03:35:40
小崎 資広 (KOSAKI Motohiro) @kosaki55tea

@frsyuki Thread.interruptで止まるメソッド一覧はドキュメントに明記してあると思うが docs.oracle.com/javase/jp/6/ap…()

2014-08-05 03:35:52
Sadayuki Furuhashi @frsyuki

InterruptibleChannelというインタフェースがある。SocketChannelやFileChannelはコレを継承しているので、interrupt可能とな。 docs.oracle.com/javase/7/docs/…

2014-08-05 03:40:14
Sadayuki Furuhashi @frsyuki

ふむ! 例えばFileChannelからのreadでブロックしているスレッドがinterrupt()されたらClosedByInterruptExceptionか。ではFileChannelをChannels.wrapしたInputStreamはどうなるかな。

2014-08-05 03:42:14
小崎 資広 (KOSAKI Motohiro) @kosaki55tea

@frsyuki まず、try catch の中にいるかどうかもわかんないのに、interruptedIOException 上がってきても困るだろうとか、そのへんか筋悪臭がする

2014-08-05 03:42:16
Sadayuki Furuhashi @frsyuki

@kosaki55tea あーInterruptedIOExceptionを発生させたいのでは無くて、発生したら困る(けどクラスは存在している)から、どんな条件で発生するかを調べておきたかったのです

2014-08-05 03:43:32
Sadayuki Furuhashi @frsyuki

あーコレはFileInputStreamが繋がった先がptyだからかな。Mac OS Xのptyの挙動がおかしいのはOS X 10.7くらいで確認したけども、まぁいいや。

2014-08-05 03:54:09
Sadayuki Furuhashi @frsyuki

ほう。FileInputChannel.readは中断可能では無いけど、FileChannelをChannels.newInputStreamでラップしたInputStreamのraedは、interrupt()するとClosedByInterruptExceptionを投げる。

2014-08-05 04:03:26
Sadayuki Furuhashi @frsyuki

InterruptibleChannel.readは、interrupt()されるとチャネルをcloseした上でClosedByInterruptExceptionを投げるから、ClosedByInterruptExceptionを受け取ったら、そのチャネルは既にclose済み。

2014-08-05 04:05:41
Sadayuki Furuhashi @frsyuki

InterruptibleChannel.readは、interrupt()されるとチャネルをcloseした上でClosedByInterruptExceptionを投げるから、ClosedByInterruptExceptionを受け取ったら、そのチャネルは既にclose済み。

2014-08-05 04:05:41