社会人のメモ帳

忘れたくないことアレコレ

【第3週】第3章:並列処理を理解する【Java Gold合格へ向けて】

PREV | LIST | NEXT

Java Gold合格へ向けて

黒本の第3章は『並列処理』、これをさらに細分化すると下記の12つに分かれる(黒本より抜粋)。

  1. RunnableインタフェースとThreadクラスを使った並行処理
  2. スレッドプール、Executorフレームワーク
  3. ExecutorServiceインタフェース
  4. ScheduleExecutorServiceインタフェース
  5. Executorクラス
  6. Futureインタフェース
  7. Callableインタフェース
  8. CyclicBarrierクラス
  9. synchronizedキーワード
  10. 原子性、java.util.concurrent.atomicパッケージのクラス
  11. スレッドセーフ、CopyOnWriteArrayListクラス
  12. ReentrantLookクラス

そもそもここでいうところの並列処理とは、Javaで提供されている単一の処理を複数のスレッドに分割して実行することができるマルチスレッドのことを指す。これらの話を理解するには前提知識が多く(スレッドとは? インタフェースとは? スケジューリングとは? etc)、それらについて学習してから覚えるのが理想だろう。本記事ではそれら前提知識について、自分なりの理解を言語化してまとめたい。

用語の理解を進める

  • プロセス…コンピュータ上で動く個々のプログラム
  • スケジューリング…リソースを効率良くつかうためのプロセス管理機能
  • スレッド…軽量プロセスとも呼ばれるスケジューリングの単位

コンピュータというのは様々な機能を実現することが期待されているが、その期待に応えるためには複数のプロセスを同時に実行することや、少ない資源(メモリなど)をやり繰りすることが求められる。それら『複数プロセスの同時実行』や『少ない資源のやり繰り』の実現に際して、スケジューリングによるプロセス管理が鍵を握る。プロセス、つまりは実行されるプログラムの単位はスレッドと呼ばれるのだが、複数のスレッドに対して同時に効率良く行えるように分割して実行することをマルチスレッドというのだ。 このマルチスレッドの機能をJacaでは提供しており、コーディングによって実行することが可能だ。そんなマルチスレッドには注意しなければならないことが多々ある。

  • スレッドの無駄遣い……無駄なスレッドの生成
  • 競合…複数のスレッドで1つのインスタンスを共有する
  • デッドロックインスタンスにアクセスしようとした際、別のスレッドにロックされてアクセスできなくなること

スレッドの無駄遣いは、実行を終えてもう処理を終えたはずのスレッドが残り続けて資源の無駄となってしまうことである。これを防ぐためにスレッドセーフが用意されている。スレッドプールは複数個の空のスレッドを作っておき、そのスレッドにタスクを与えて実行させる。待機する空のスレッドと、タスクを実行するスレッドを分けることで問題を解決できるという訳だ。

競合は、インスタンスに保持している値が別のスレッドによって書き換えられ、期待とは違う挙動をしてしまうことである。これを防ぐために排他制御が用意されている。これはあるスレッドが処理している間は、別のスレッドがその処理を実行しないように待機させることで意図しない動作が起きないようにすることである。

  • synchronizedキーワード

デッドロックは、排他制御によってアクセスできないようにされたインスタンスが利用できなくなることである。これを防ぐためにロックする順番を揃える等、コーディング時に考慮する必要がある。そのために原子性スレッドセーフといった概念を理解することが求められる。

  • 原子性、java.util.concurrent.atomicパッケージのクラス
  • スレッドセーフ、CopyOnWriteArrayListクラス
  • ReentrantLookクラス

対策に向けて

それにしてもどこから手を付けるべきだろうか……とりあえず並列処理を実装して動かしてみようかと思う。その勉強の流れとしては下記のような流れを考えている。

  1. とにかく実装してみる マルチスレッドを実行する方法は、黒本において2つ紹介されている。その2つをとりあえず動かしてみる。
  2. エラーを起こしてみる スレッドの無駄遣いや競合、デッドロックを起こしてみる。
  3. エラーを解消する 2で起こしたエラーを解消するためにJavaで用意されている機能を使ってみる、