ひだまりソケットは壊れない

ソフトウェア開発に関する話を書きます。 最近は主に Android アプリ、Windows アプリ (UWP アプリ)、Java 関係です。

まじめなことを書くつもりでやっています。 適当なことは 「一角獣は夜に啼く」 に書いています。

読んだ: Java 並行処理プログラミング / ブライアン・ゲーツ、ダグ・リー、他 著、岩谷宏 訳

Java の並行処理プログラミングについての書籍を読みました。 2006 年の本なので結構古いですが、内容的には今でも十分通用するものですし、世間からも高く評価されてるみたいですね。 内容的にはかなり良かったです。

Java並行処理プログラミング ―その「基盤」と「最新API」を究める―

Java並行処理プログラミング ―その「基盤」と「最新API」を究める―

内容紹介

簡単に内容を紹介します。 本書は全 4 部、16 章構成となっています。

序章

まず、第 1 章は序章ということで、並行処理の歴史と、マルチスレッドプログラミングの必要性や、利点と欠点などが述べられています。 IO 待ちすることが多い処理を複数実行する場合は、マルチスレッドにすることで CPU 資源を無駄にしない、とか、GUI プログラミングの場合は基本的GUI 部品を触るのは 1 つのスレッドのみからで、他の時間のかかる処理などは別のスレッドで実行するようになっているから自然とマルチスレッドになるとか、そういう話です。 欠点としては、当然のことながらソフトウェアの複雑性が上がる、という感じです。

第 1 部 基礎編

続く 2 章からは第 1 部 「基礎編」 です。

第 2 章 「スレッドセーフ」 では、ソフトウェア部品をスレッドセーフに作らなければいけない理由や、どのようにすればスレッドセーフになるかの説明がされます。 例えば、オブジェクトの状態を複数のスレッドで共有しなければ良い、とか、複数のスレッドで状態を共有する場合は、その状態をロックでガードする、とかですね。 処理のアトミック性や生存と実行性能についても説明があります。

3 章 「オブジェクトを共有する」 では、可視性の説明や揮発性変数 (volatile 変数) について、それから不可変性 (final 修飾) についてやオブジェクトを安全に公開する方法についてなど説明されています。 可視性の概念は Java を触り始めた人は知らないことも多いと思うので結構重要ですね。

4 章ではスレッドセーフなクラスを設計する方法や、スレッドセーフでないクラスをスレッドセーフに使用する方法 (スレッド拘束にするとか) などが述べられています。 同期化のポリシーをちゃんとドキュメント化せよ、というようなことも書かれています。 (個人的にはドキュメント化されていなければスレッドセーフではないとみなすべき、と思ったりします。)

5 章では Java API に含まれる並行処理プログラミングのための様々なクラスが紹介されます。 主には Java SE 5 で導入された java.util.concurrent パッケージに含まれるものです。

第 2 部 並行アプリケーションの構造を作る

6 章から 9 章までが第 2 部です。 ここでは、アプリケーション全体 (あるいはある程度まとまったアプリケーションの部分) の並行処理について述べられます。 ざっくりと書くと次のような話があります。

  • どういう部分を並行処理にすべきなのか
  • 実行されるタスクとスレッドの管理は別に行うべきであるという話 (スレッド管理は Executor を使って行う)
    • スレッドの所有者が誰なのか、設計上明確にしておくべき
  • タスクはキャンセル可能にすべきであり、Executor はシャットダウン可能にすべきである、という話
    • Java のスレッドには interrupted 状態がある
  • スレッドプールを使う
  • GUI プログラミングとシングルスレッド設計について

ここら辺はアプリケーション全体の設計に絡んでくるところなのでなかなか難しい領域ですし、読みごたえがありました。

第 3 部 生存、実行性能、試験

10 章から 13 章までは、生存についてや実行性能、試験といったソフトウェアの品質についての説明です。

並行処理がある場合、デッドロックによりソフトウェアの処理が止まってしまうという可能性があります。 できるだけ、ロックを保有せずにメソッドを呼び出す 「オープンコール」 を行うように気を付けることで、デッドロックしないコードを書きやすくなります。 また、資源が無限にある場合は問題ないようなコードになっていても、実際上は資源が有限で、資源の枯渇によって飢餓状態になって処理が止まってしまうこともあります。 スレッドプールのスレッド数に制限があって、スレッドプールで動いているタスクが、スレッドプールの待機列にあるタスクの処理を待っていて処理が止まる、なんていう場合も紹介されていて、なかなか難しいなーという感じです。

11 章、実行性能についての章では、コンテキストスイッチが多いと並列化しても実行性能が上がらない可能性があるとか、ロックの粒度を小さくすると良いとか、そういう話が書かれています。 Java API に含まれているスレッドセーフなコレクションクラスは、かなり性能がいいのでそっちを使うようにすべき、とか。

12 章では並行処理のテストについて述べられています。 そもそも並行処理のテストは難しいとか、Java には JIT があるので性能評価しづらいとか、そういう感じです。 あとは計測のための処理がスレッド間の同期化に繋がってしまうことがあって、その場合並行処理のテストがちゃんとできないわけなので気を付ける必要があるとか、まあ難しいですね。

第 4 部、高度な話題

4 部は高度な話題ということで、明示的なロック (synchronized ブロックではなく Lock) についてや、カスタムシンクロナイザについて、アトミック変数とノンブロッキング同期化、そして Java のメモリモデルについて説明されています。

高度な話題となっていますが、特にアトミック変数についてや Java のメモリモデルについては、Java を使う人ならわりと誰でも知っているべきことなんじゃないかな、と思います。

感想

Java の並行処理についてよくまとまっています。 ここまでまとまってる書籍は他にないように思いますので、古いことは古いですが、Java で並行処理を書くなら読んでおくといいでしょう。 (そして Java を使うのに並行処理をしないなんてことはほとんどないと思うので、まあ Java を書く人は全員読んでおいていいんじゃないですかね。) 内容的には文句なしです。

Android アプリ開発なんかでもマルチスレッド処理が必要になる場面が多いですので、Android アプリの開発者も読んでおくと良さそうです。

一方で、話の展開についてはちょっと微妙かなぁという気になります。 展開が冗長なところが多く、結論に達するまでだめな例がいくつも出てくるなんてことがあるので、読んでいてもどかしい気持ちになることが多かったです。 しかし逆に、並行処理プログラミングについてあまり知識がない状態ならば、そういう展開なのは理解の助けになるかもしれません。

他の書籍の紹介

並行処理に関して私が読んだことのある他の書籍も紹介しておきます。

Java 言語で学ぶデザインパターン入門 マルチスレッド編

Java 並行処理プログラミング』 と比べ、内容は易し目です。 図なども多く、わかりやすいです。 並行処理について (他言語でも) あまり経験がないのであれば、『Java 並行処理プログラミング』 よりも先にこちらを読むといいでしょう。

ただ、java.util.concurrent パッケージの説明が付録にあるだけであり、低級 API が多く使われているので、勉強には最適ですが実用的かというと微妙かもしれません。 この書籍で並行処理について勉強したうえで、実用的な内容は 『Java 並行処理プログラミング』 の方で学ぶ、という流れが良さそうです。

並行コンピューティング技法

並行コンピューティング技法 ―実践マルチコア/マルチスレッドプログラミング

並行コンピューティング技法 ―実践マルチコア/マルチスレッドプログラミング

並行処理の基礎的な話と、アルゴリズムの話が主です。 言語に依らない並行処理の全般的なところを知りたいなら読むといいかもしれません。

その他の書評