同期ブロックによる解決
|
|
同期ブロックによる解決法
以下は、PocketMoneyサーブレットのperformTaskメソッドの問題の個所を抜き出したものである。
問題のコード |
//初めてではない、要求されたお金を出して残りをクライアントにかえす int deduct = 0; //deductはローカル変数としなければならない try{
deduct =
Integer.valueOf(request.getParameter("needMoney")).intValue(); out.println(deduct
+ "円の要求");
//Thread.sleep((long)(Math.random() * 10000)); //10秒までのランダムな待ち時間をつくる }catch(NumberFormatException e){} if (pocketMoney > deduct){ out.println(pocketMoney + "円の残金から" + deduct +
"円を出します(残り" + (pocketMoney-deduct) + "円)"); Thread.sleep((long)(Math.random() * 10000)); //10秒までのランダムな待ち時間をつくる pocketMoney = pocketMoney - deduct; out.println(deduct + "円を出しました(残り" + pocketMoney
+ "円)"); }else{ out.println(pocketMoney + "円しか残っていません"); } |
ここでは最初のsleepはコメント・アウトされている。またdeduct(引き出し金額)という変数もローカル変数としてこのメソッドのなかで定義されている。問題は複数のスレッドが母親のポケットに手を突っ込んでいる赤で塗り分けた部分である。このブロックが唯ひとつのスレッドにしか実行できないようにするには、同期化ブロックを使用する。
同期ブロック |
synchronized
(this){ if (pocketMoney > deduct){
out.println(pocketMoney + "円の残金から" + deduct + "円を出します(残り"
+ (pocketMoney-deduct) + "円)");
Thread.sleep((long)(Math.random() * 10000)); //10秒までのランダムな待ち時間をつくる
pocketMoney = pocketMoney - deduct;
out.println(deduct + "円を出しました(残り" + pocketMoney + "円)"); }else{
out.println(pocketMoney + "円しか残っていません"); } } |
(this)は同期ロックの対象がPocketMoneyサーブレットのオブジェクトであることを示すが、その意味は後で説明する。こうすれば問題が解決されることを、このサーブレットを複数のブラウザからアクセスして皆さん確認していただきたい。
同期ブロックは、このように共有資源をアクセスする部分がまとまっていれば、簡単な方法である。