プログラミング応用b 第11回 『スレッド2』 |
●順序づけによるデッドロック回避
デッドロックは,複数の同期コードで,複数のロック用オブジェクトからロックを取得
するとき,あべこべの順番でロックを取得するために発生するのである。
先ほどの,「太郎君と花子さんに1枚の紙と1本の鉛筆を渡して"こんにちは"と書け」と命令
する例で言うと,「太郎君が紙を最初に取り,次に太郎君が鉛筆が必要にもかかわらず,花子
さんが鉛筆をとってしまった」のが原因である。これを解決するには,命令に
「必ず紙から手に取り,次に鉛筆を手に取ること」
と付け加えればよい。そうすれば,太郎君が最初に紙を手にした後で,花子さんは太郎君が紙を
手放すまで待つことになる。太郎君が紙の次に鉛筆を取って紙に"こんにちは"と書いて,紙と
鉛筆を手放すと,花子さんが紙・鉛筆の順で手にとって紙に"こんにちは"と書くことになり,
めでたく2人とも目的を達することが出来る。
(これも実演すると良く分かる。友人三人でやってみよう。そのうち一人は命令を下す役。)
List 8〜10 の例では,a1 から a2 へ送金する同期コードでは
a1 のロックを取得 → a2 のロックを所得
という順番でロックを取得したが, a2 から a1 へ送金する同期コードでは,
a2 のロックを取得 → a1 のロックを所得
という順番でロックを取得していた。これがデッドロックの原因である。
もし,両方の同期コードが
a1 のロックを取得 → a2 のロックを所得
という順番でロックを取得しようとすれば,デッドロックは起こらない。
そこで,デッドロックを解決するには,ロック用オブジェクトに一意の識別番号をつけ,その識別番号の
小さい順からロックするようにすればいいことになる。この方針に基づき,実際に List 8 〜 10 の
デッドロックを回避してみよう。
この送金プログラムの例では,ロック用オブジェクトは, List 8 で定義されている Account のオブ
ジェクトを使用していた(List 9-②)。さいわい,Account 型オブジェクトには口座番号という一意の
番号が割り振られている。つまり,口座番号の小さい方からロックを取得するようにすればいいわけで
ある。
List 9 を改良したのが, List 11 である。List 11-① で,
・口座番号が小さい方の口座オブジェクトを firstLocked に設定
・口座番号が大きい方の口座オブジェクトを secondLocked に設定
している。そして,List 11-② では,まず firstLocked からロックを取得し,つぎに secondLocked
からロックを取得するようになっている。
List 8,List 10,Lis 11の組み合わせでプログラムを実行すると,デッドロックが発生せず,正常に
プログラムが動作することがわかる。
List 11 TransferTransaction.java
次に進む