Java Gold合格へ向けて
黒本の第3章は『並列処理』、これをさらに細分化すると下記の12つに分かれる(黒本より抜粋)。
- RunnableインタフェースとThreadクラスを使った並行処理
- スレッドプール、Executorフレームワーク
- ExecutorServiceインタフェース
- ScheduleExecutorServiceインタフェース
- Executorクラス
- Futureインタフェース
- Callableインタフェース
- CyclicBarrierクラス
- synchronizedキーワード
- 原子性、java.util.concurrent.atomicパッケージのクラス
- スレッドセーフ、CopyOnWriteArrayListクラス
- ReentrantLookクラス
そもそもここでいうところの並列処理とは、Javaで提供されている単一の処理を複数のスレッドに分割して実行することができるマルチスレッドのことを指す。これらの話を理解するには前提知識が多く(スレッドとは? インタフェースとは? スケジューリングとは? etc)、それらについて学習してから覚えるのが理想だろう。本記事ではそれら前提知識について、自分なりの理解を言語化してまとめたい。
用語の理解を進める
- プロセス…コンピュータ上で動く個々のプログラム
- スケジューリング…リソースを効率良くつかうためのプロセス管理機能
- スレッド…軽量プロセスとも呼ばれるスケジューリングの単位
コンピュータというのは様々な機能を実現することが期待されているが、その期待に応えるためには複数のプロセスを同時に実行することや、少ない資源(メモリなど)をやり繰りすることが求められる。それら『複数プロセスの同時実行』や『少ない資源のやり繰り』の実現に際して、スケジューリングによるプロセス管理が鍵を握る。プロセス、つまりは実行されるプログラムの単位はスレッドと呼ばれるのだが、複数のスレッドに対して同時に効率良く行えるように分割して実行することをマルチスレッドというのだ。 このマルチスレッドの機能をJacaでは提供しており、コーディングによって実行することが可能だ。そんなマルチスレッドには注意しなければならないことが多々ある。
スレッドの無駄遣いは、実行を終えてもう処理を終えたはずのスレッドが残り続けて資源の無駄となってしまうことである。これを防ぐためにスレッドセーフが用意されている。スレッドプールは複数個の空のスレッドを作っておき、そのスレッドにタスクを与えて実行させる。待機する空のスレッドと、タスクを実行するスレッドを分けることで問題を解決できるという訳だ。
- スレッドプール、Executorフレームワーク
競合は、インスタンスに保持している値が別のスレッドによって書き換えられ、期待とは違う挙動をしてしまうことである。これを防ぐために排他制御が用意されている。これはあるスレッドが処理している間は、別のスレッドがその処理を実行しないように待機させることで意図しない動作が起きないようにすることである。
- synchronizedキーワード
デッドロックは、排他制御によってアクセスできないようにされたインスタンスが利用できなくなることである。これを防ぐためにロックする順番を揃える等、コーディング時に考慮する必要がある。そのために原子性やスレッドセーフといった概念を理解することが求められる。
- 原子性、java.util.concurrent.atomicパッケージのクラス
- スレッドセーフ、CopyOnWriteArrayListクラス
- ReentrantLookクラス
対策に向けて
それにしてもどこから手を付けるべきだろうか……とりあえず並列処理を実装して動かしてみようかと思う。その勉強の流れとしては下記のような流れを考えている。