Один из примеров, который я могу придумать, - это сценарий «Стол, фонарик и батарейки». Представьте себе фонарик и пару батареек, размещенных на столе. Если вы подойдете к этому столу и возьмете батарейки, пока у другого человека есть фонарик, вы оба будете вынуждены неловко смотреть друг на друга, ожидая, кто первым положит свой предмет обратно на стол. Это пример тупика. Вы и этот человек ждете ресурсов, но никто из вас не отказывается от своих ресурсов.
Точно так же в программе взаимоблокировка возникает, когда два или более потока (вы и другой человек) ждут освобождения двух или более блокировок (фонарик и батарейки), а обстоятельства в программе таковы, что блокировки никогда не освобождаются ( у вас обоих есть одна часть головоломки).
Если вы знаете java, то можете представить эту проблему следующим образом:
import java.util.concurrent.locks.*;
public class Deadlock1 {
public static class Table {
private static Lock Flashlight = new ReentrantLock();
private static Lock Batteries = new ReentrantLock();
public static void giveFlashLightAndBatteries() {
try {
Flashlight.lock();
Batteries.lock();
System.out.println("Lights on");
} finally {
Batteries.unlock();
Flashlight.unlock();
}
}
public static void giveBatteriesAndFlashLight() {
try {
Batteries.lock();
Flashlight.lock();
System.out.println("Lights on");
} finally {
Flashlight.unlock();
Batteries.unlock();
}
}
}
public static void main(String[] args) {
// This thread represents person one
new Thread(new Runnable() {
public void run() { Table.giveFlashLightAndBatteries(); }
}).start();
// This thread represents person two
new Thread(new Runnable() {
public void run() { Table.giveBatteriesAndFlashLight(); }
}).start();
}
}
Если вы запустите этот пример, вы заметите, что иногда все работает хорошо и правильно. Но иногда ваша программа просто ничего не печатает. Это потому, что у одного человека есть батарейки, а у другого есть фонарик, который не позволяет им включить фонарик, вызывая тупик.
Этот пример похож на пример, приведенный в руководствах по java: http://docs.oracle.com/javase/tutorial/essential/concurrency/deadlock.html
Другой пример - пример цикла:
public class Deadlock2 {
public static class Loop {
private static boolean done = false;
public static synchronized void startLoop() throws InterruptedException {
while(!done) {
Thread.sleep(1000);
System.out.println("Not done");
}
}
public static synchronized void stopLoop() {
done = true;
}
}
public static void main(String[] args) {
// This thread starts the loop
new Thread(new Runnable() {
public void run() {
try {
Loop.startLoop();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
// This thread stops the loop
new Thread(new Runnable() {
public void run() {
Loop.stopLoop();
}
}).start();
}
}
Этот пример может либо печатать «Not done» снова и снова, либо он никогда не может печатать «Not done» вообще. Первое происходит потому, что первый поток получает блокировку класса и никогда не снимает ее, предотвращая доступ к «stopLoop» для второго потока. И последнее происходит потому, что второй поток запускается раньше первого потока, в результате чего переменная done становится истинной до того, как первый поток выполнится.