デッドロックの作成: 以下のコードは、デッドロックを作成する例です。
public class DeadlockExample {
private static Object lock1 = new Object();
private static Object lock2 = new Object();
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
synchronized (lock1) {
System.out.println("Thread 1 acquired lock1");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock2) {
System.out.println("Thread 1 acquired lock2");
}
}
});
Thread thread2 = new Thread(() -> {
synchronized (lock2) {
System.out.println("Thread 2 acquired lock2");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock1) {
System.out.println("Thread 2 acquired lock1");
}
}
});
thread1.start();
thread2.start();
}
}
上記のコードでは、2つのスレッドがそれぞれ異なる順序で lock1
と lock2
を取得しようとします。しかし、両方のスレッドが相手のロックを待っているため、デッドロックが発生します。
デッドロックの修正: デッドロックを修正するためには、スレッドがリソースを順番に取得するように制御する必要があります。以下に修正されたコードを示します。
public class DeadlockFixExample {
private static Object lock1 = new Object();
private static Object lock2 = new Object();
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
synchronized (lock1) {
System.out.println("Thread 1 acquired lock1");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock2) {
System.out.println("Thread 1 acquired lock2");
// ロックを解放してから次のスレッドが取得できるようにする
}
}
});
Thread thread2 = new Thread(() -> {
synchronized (lock1) {
System.out.println("Thread 2 acquired lock1");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock2) {
System.out.println("Thread 2 acquired lock2");
// ロックを解放してから次のスレッドが取得できるようにする
}
}
});
thread1.start();
thread2.start();
}
}
修正されたコードでは、lock1
を取得したスレッドが完全に処理を終えてから lock2
を取得するようになっています。同様に、もう一方のスレッドも lock1
を取得したスレッドが完全に終了するまで待ちます。これにより、デッドロックが回避されます。
以上が、Javaでデッドロックを作成し修正する方法です。デッドロックの発生を防ぐためには、スレッドの順序付けやロックの取得方法を慎重に設計する必要があります。