-PipedOutputStreamで嵌る

01: @Test
02: public void testPipe() throws Exception {
03:     PipedOutputStream out = new PipedOutputStream();
04:     PipedInputStream in = new PipedInputStream(out);
05:     out.write("0123456789".getBytes());
06:     // out.close();
07:     while(true) {
08:         byte[] buffer = new byte[8];
09:         int len = in.read(buffer, 0, buffer.length);
10:         if(len <= 0) {
11:             break;
12:         }
13:         System.out.write(buffer, 0, len);
14:     }
15:     System.out.println();
16:     System.out.println("EOF");
17:     in.close();
18: }

上記のコードは無限ループになってしまい、動作しません。無限ループもメソッド中に書いたもの(7行-14行)ではなく、9行目のread()メソッドの中で無限ループに落ちて、ブロックされたように止まります。原因は、6行目にコメントで答えが書いてありますが、PipedOutputStream#close()を呼んでいないため。close()でEOFを書くまでは、outに非同期に書きだして、inで書かれたそばから読み出すということが可能です。まさにパイプ処理ですね。当然バッファへの書き込みはちゃんとsynchronizedされています。
修正としては、上記コード6行目のコメントをトグルすればOKです。こんな例ではミエミエですが、Writer他でラップされてコードが散ってたので見逃してしまった。かなり昔に同じ問題(バグ)に遭遇し解決したことがあったんだけど、その経験を思い出したのはデバッガで時間かけて追っかけて後でした。今後もあまりPipedOutputStreamなんて使わないと思うけど、BLOGに備忘録として残しておこう。今回はSVNKitとMaven-Modelを組み合わせてリポジトリ中のpom.xmlを読み書きするのに使っています。ちなみに、PipedInputStreamのデフォルトのバッファサイズは1024バイト。