torutkのブログ

ソフトウェア・エンジニアのブログ

Javaちょっと調べたメモ(ファイルのMD5、ソケットのinterrupt)

JDK6 Update10 Beta12(AMD64用)をインストールしたらインストーラが途中でエラーとなりました。ダウンロードしたファイルが完全ではないかと疑い、ハッシュ値MD5)を確認しようと思い、JavaでファイルのMD5ハッシュ値を取る方法を調べました。

また、別件で作っているプログラムでソケットの受信を開始/停止できるようにしたかったのですが、スレッドに割り込み(interrupt)をしてもソケットのブロックした読み出しはInterruptedExceptionになりません。Java読書会の前回本「Java並行処理プログラミング」を読み直してソケットの同期I/Oでブロックしているスレッドをキャンセルする方法を確認しました。

ファイルのMD5を取る

以下の2つのクラスを使えば数行で実現可能でした。

  • java.security.MessageDigestクラス
  • java.security.DigestInputStreamクラス
        String filename = ...

        MessageDigest md = MessageDigest.getInstance("MD5");
        DigestInputStream inStream = new DigestInputStream(
            new BufferedInputStream(new FileInputStream(filename)), md
        );

        while (inStream.read() != -1) {
        }
        byte[] digest = md.digest();
        inStream.close();

        for (int i=0; i<digest.length; i++) {
            System.out.printf("%02x", digest[i]);
        }

ソケットの同期I/Oでブロック中のスレッドのキャンセル

書籍「Java並行処理プログラミング」の7-1-6節 インタラプトできないブロッキングの扱い方で、直接インタラプションに応答しないブロックの例として以下が挙げられています。

  • java.ioの同期ソケットI/O
  • java.nioの同期I/O
  • Selectorによる非同期I/O

ソケットI/Oの場合は、ソケットをクローズすることでInputStream/OutputStreamのread/writeがSocketExceptionをスローしてブロックが解けるとあります。

ということで、ScheduledFutureのcancelを呼び出したい箇所でsocketをcloseさせることで暫定的なスレッドのキャンセルが実現できました。

書籍には、Threadを拡張してinterruptメソッドをオーバーライドしsocketをcloseするサンプルと、ThreadPoolExecutorを拡張してnewTaskForメソッドをオーバーライドするとともにCallableを拡張して実装する抽象クラスSocketUsingTaskのサンプルが載っています。