Одним із прикладів, про який я можу подумати, є сценарій «Стіл», «Ліхтарик» та «Акумулятори». Уявіть собі ліхтарик і пару батарейок, які розміщені вгорі на столі. Якщо вам довелося підійти до цього столу і взяти батарейки, поки у іншої людини є ліхтарик, ви обоє будете змушені незграбно дивитись один на одного, чекаючи, хто спочатку покладе свій предмет назад на стіл. Це приклад тупикової ситуації. Ви та людина чекаєте ресурсів, але ніхто з вас не відмовляється від їх ресурсу.
Подібним чином, у програмі відбувається глухий кут, коли два або більше потоків (ви та інша особа) чекаєте звільнення двох або більше замків (ліхтарик та акумулятори), а обставини програми такі, що замки ніколи не звільняються ( у вас обох є одна частина головоломки).
Якщо ви знаєте 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();
}
}
Цей приклад може надрукувати "Не зроблено" знову і знову, або взагалі ніколи не друкувати "Не зроблено". Перший трапляється тому, що перший потік отримує блокування класу і ніколи не звільняє його, перешкоджаючи доступу до 'stopLoop' з боку другого потоку. І останнє трапляється тому, що другий потік почався до першого потоку, що спричинило зміну 'done' до істини перед тим, як перший потік буде виконаний.