デッドロックを引き起こすプログラムの例:
public class DeadlockExample {
private static Object resource1 = new Object();
private static Object resource2 = new Object();
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
synchronized (resource1) {
System.out.println("スレッド1: resource1をロックしました");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (resource2) {
System.out.println("スレッド1: resource2をロックしました");
}
}
});
Thread thread2 = new Thread(() -> {
synchronized (resource2) {
System.out.println("スレッド2: resource2をロックしました");
synchronized (resource1) {
System.out.println("スレッド2: resource1をロックしました");
}
}
});
thread1.start();
thread2.start();
}
}
上記のプログラムでは、2つのスレッドがそれぞれresource1
とresource2
をロックしようとしていますが、順番が逆になっています。つまり、スレッド1がresource1
をロックし、スレッド2がresource2
をロックしようとすると同時に、スレッド2がresource1
を待っています。同様に、スレッド1もresource2
を待っています。これにより、デッドロックが発生します。
デッドロックの修正方法:
デッドロックを解決するためには、以下のようなアプローチを取ることができます。
-
リソースの順序付け: スレッドが複数のリソースを要求する場合、リソースに対する一貫した順序付けを行います。つまり、スレッドは常に同じ順序でリソースを要求するようにします。
-
リソースのタイムアウト: スレッドが一定時間内に必要なリソースを取得できない場合、リソースを解放して他のスレッドが使用できるようにします。
-
スレッドの割り込み: スレッドがデッドロックに陥った場合、他のスレッドから割り込みを行い、デッドロックから脱出できるようにします。
修正されたプログラムの例:
public class DeadlockFixExample {
private static Object resource1 = new Object();
private static Object resource2 = new Object();
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
synchronized (resource1) {
System.out.println("スレッド1: resource1をロックしました");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (resource2) {
System.out.println("スレッド1: resource2をロックしました");
}
}
});
Thread thread2 = new Thread(() -> {
synchronized (resource1) {
System.out.println("スレッド2: resource1をロックしました");
synchronized (resource2) {
System.out.println("スレッド2: resource2をロックしました");
}
}
});
thread1.start();
thread2.start();
}
}
修正後のプログラムでは、スレッド1とスレッド2がリソースのロックを要求する順序が一致しています。スレッド1はresource1
をロックし、スレッド2も同じ順序でresource1
をロックするように修正しました。
また、デッドロックを回避するために、スレッドが一定時間内に必要なリソースを取得できない場合にタイムアウトを設定することも考えられます。これにはtryLock()
メソッドやLock
インターフェースを使用する方法があります。
デッドロックの修正方法は状況によって異なる場合があります。デッドロックを回避するための最適な方法は、アプリケーションの要件やコードの特性によって異なる場合があります。