Взаимная блокировка – это ситуация, при которой два или более потоков заблокированы навсегда, ожидая друг друга.
Для понимания того, как это работает на практике рассмотрим пример простого приложения.
Пример:
Класс DeadLockDemo
public class DeadLockDemo {
public static final Object Lock1 = new Object();
public static final Object Lock2 = new Object();
public static void main(String[] args) {
DeadThreadOne threadOne = new DeadThreadOne();
DeadThreadTwo threadTwo = new DeadThreadTwo();
threadOne.start();
threadTwo.start();
}
private static class DeadThreadOne extends Thread {
public void run() {
synchronized (Lock1) {
System.out.println("DeadThreadOne is holding LOCK 1...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("DeadThreadOne is waiting for Lock 2...");
synchronized (Lock2) {
System.out.println("DeadThreadOne is holding Lock 1 and Lock 2...");
}
}
}
}
private static class DeadThreadTwo extends Thread {
public void run() {
synchronized (Lock2) {
System.out.println("DeadThreadTwo is holding LOCK 2...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("DeadThreadOne is waiting for Lock 1...");
synchronized (Lock1) {
System.out.println("DeadThreadOne is holding Lock 1 and Lock 2...");
}
}
}
}
}
В результате работы этой программы, мы получим, примерно, следующий результат:
DeadThreadOne is holding LOCK 1...
DeadThreadTwo is holding LOCK 2...
DeadThreadOne is waiting for Lock 2...
DeadThreadOne is waiting for Lock 1...
Программа будет находиться в таком состоянии до момента её ручной остановки, потому что оба потока ожидают друг друга для того, чтобы продолжить свою работу.
Рассмотрим пример приложения, в котором показано, как избежать такой ситуации.
Пример:
Класс SolveDeadLock
public class SolveDeadLock {
public static final Object Lock1 = new Object();
public static final Object Lock2 = new Object();
public static void main(String args[]) {
ThreadOne threadOne = new ThreadOne();
ThreadTwo threadTwo = new ThreadTwo();
threadOne.start();
threadTwo.start();
}
private static class ThreadOne extends Thread {
public void run() {
synchronized (Lock1) {
System.out.println("ThreadOne is holding lock 1...");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("ThreadOne is waiting for lock 2...");
synchronized (Lock2) {
System.out.println("ThreadOne is holding lock 1 & 2...");
}
}
}
}
private static class ThreadTwo extends Thread {
public void run() {
synchronized (Lock1) {
System.out.println("ThreadTwo is holding lock 1...");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("ThreadOne is waiting for lock 2......");
synchronized (Lock2) {
System.out.println("ThreadTwo is holding lock 1 & 2...");
}
}
}
}
}
В результате работы этой программы, мы получим, примерно, следующий результат:
/*Some System Messages*/
ThreadOne is holding lock 1...
ThreadOne is waiting for lock 2...
ThreadOne is holding lock 1 & 2...
ThreadTwo is holding lock 1...
ThreadOne is waiting for lock 2......
ThreadTwo is holding lock 1 & 2...
В этом разделе мы изучили понятие взаимной блокировки и рассмотрели пример приложения с её реализацией и пример приложения, в котором показано, как избежать взаимной блокировки.