本日、デッドロックの恐れのあるコード二箇所を修正しました。
デッドロックとは、複数のスレッドがお互いにロックの解放を永久に待ち続けてしまう現象のことを言います。
デッドロックを回避するための一般的な手順は、
1. 複数のオブジェクトに対して同期制御を行う場合がある場合は、ロックの順序をあらかじめ決定しておく
2. 各スレッドはその順序でロックを獲得する。
(Sun Educational Services STUDENT GUIDE JavaプログラミングⅡより)
実は教科書に書いてあるような絵に描いたようなデッドロックはSOBAでは見かけません。
もっと難しくて根の深いものです。本日、SOBA Project,Inc.のD氏と解いたのおよそ以下のようなデッドロックです。
public class DeadLock {
private static Logger logger = Logger.getLogger("lock");
private Hashtable hash = new Hashtable();
public DeadLock() {
final ValueObject obj = new ValueObject();
new Thread(new Runnable() {
public void run() {
while (true) {
logger.entering("", "", hash);
System.out.println("a");
}
}
}).start();
while (true) {
hash.put(obj, "value");
System.out.println("b");
}
}
public static void main(String[] args) {
try {
FileHandler fh = new FileHandler("deadlock.log");
fh.setFormatter(new SimpleFormatter());
logger.addHandler(fh);
logger.setLevel(Level.FINER);
new DeadLock();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public class ValueObject {
public boolean equals(Object obj) {
System.out.println("put()中から呼ばれます。");
logger.entering("ValueObject", "equals", obj);
return super.equals(obj);
}
}
}
(コード提供:D氏)
mainスレッドでHashtable.put()のロックしてから、ログ出力用のFileHandlerのロックします。
また、別スレッドでは、ログ出力用のFileHandlerのロックしてから、Hashtable.toString()のロックします。
このサンプルはかなり簡易に書いてあるので容易ですが、SOBAのような大規模なフレームワークではなかなか不具合も発生せず、発生したとしても原因の特定は容易ではありません。今回は、JProfilerとEclipseにより場所を特定して修正しました。