Jの衝動書き日記

さらりーまんSEの日記でございます。

Java並行処理プログラミング 勉強会まとめ その3 処理をタスク化する

スレッドに関する超良書、Java並行処理プログラミングで学んだことをまとめたものである。Javaだとスレッドを作る=クラスを作るとなるため、イマイチピンとこなかったが、ようやく理解が進んだ・・・と思う。

タスクとは?

独立して行いたい処理とそれを行うための専用のデータをまとめたものを指す。平たくいえば、データ+処理=オブジェクトであるため、タスクもオブジェクトでもある。これにCPUを割り当てるとスレッドとして動作する。Javaの場合、Threadクラスを作成→startを実行でスレッドが動く。
さて、処理のタスク化の重要なポイントは何かというと、処理の依頼と実行を分離することである。通常は、Threadクラスを作成→startとなるため、処理の依頼(仕事(タスク)の定義)と実行は分離はしていない。分離するにはどうするかというと、タスクの作成だけを行い、その実行はフレームワークに任せるという形を取る。
Javaの場合、タスクの作成とは、Runnable(実行のみ。結果は返さない。例外も返さない。)かCallable(結果を返せる。例外も返せる。)を実装したクラスを作成することを言う。

タスク化の利点

タスク化の利点、タスクの依頼と実行を分離する価値は何があるのか? それは、実行ポリシーを簡単に指定出来る、実行ポリシーの変更も簡単に出来るという点にある。実行ポリシーは、タスクの実行のwhat,where,when,howを指定する。

  • 実行ポリシーの例
    • 並列に実行可能なタスクの数はいくつか?
    • 待ちキューに並ぶタスクの最大数はいくつか?
    • タスクをどんな順序で実行するのか?

タスクを作成し、その実行をフレームワークに任せるという形をとれば、タスクのスケジュール化が可能になり、扱うタスク量の調整が可能にもなる。タスクの依頼と実行が分離していないと、これは難しい。

タスク化に適したものは?

ポイントは以下の3点

  • 処理が同質
  • 扱うデータは独立
  • 処理に依存関係がない(並列に処理が可能)

上記3点を満たすものがタスク化に向いており、スレッドプールによる実行が適している。
タスク化の例
・ループ処理
ループの一要素がそれぞれタスクの候補になる(ループの各要素は独立するため)。各要素に実行順序などの依存関係がないことが条件。
・再起処理
再帰処理が、前の結果を必要としない場合可能

タスク化に適さないものは?

次のどれかに当てはまる場合はタスク化は避けるのが無難。

  • 処理が異質
  • 処理が逐次的
  • データが依存→順序などがある場合も依存

例えば、A→B→Cという処理あり、A、B、Cをそれぞれタスク化してもあまり効果がない。

タスクの実行は?

Java1.5以降は、Executorフレームワークがあるので、これにお任せ。自前でタスクをstartする利点はもはやほとんどない。

タスクのキャンセルについて

  • キャンセルポリシー
    • what:キャンセルのリクエストに対してどんなアクションを実行するべきか
    • when:タスクはキャンセルがリクエストされたことをいつチェックする?
    • how:タスクのキャンセルをどうやって求める?
  • インタラプションポリシー

スレッドがインタラプションをどう解釈するか?の方針

やってはいけないこと

  • 汎用的なタスクやライブラリコードでInterruptedExcetionを飲み込む

catch(InterruptedExcetion ie) {} などが駄目

  • インタラプションポリシーを実装しているコードだけがもみ消し可能

参考文献

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

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