Jednym z przykładów, które przychodzą mi do głowy, jest scenariusz Stół, latarka i baterie. Wyobraź sobie latarkę i parę baterii umieszczoną na stole. Jeśli podejdziesz do tego stołu i złapiesz baterie, podczas gdy inna osoba będzie miała latarkę, oboje będziecie zmuszeni do niezręcznego wpatrywania się w siebie, czekając, kto pierwszy położy przedmiot z powrotem na stole. To jest przykład impasu. Ty i ta osoba czekacie na zasoby, ale nikt z was nie rezygnuje z ich zasobów.
Podobnie w programie, zakleszczenie występuje, gdy dwa lub więcej wątków (Ty i druga osoba) czekają na zwolnienie dwóch lub więcej blokad (latarki i baterii), a okoliczności w programie są takie, że blokady nigdy nie są zwalniane ( oboje macie jeden element układanki).
Jeśli znasz Javę, możesz przedstawić ten problem w następujący sposób:
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();
}
}
Jeśli uruchomisz ten przykład, zauważysz, że czasami rzeczy działają dobrze i poprawnie. Ale czasami twój program po prostu niczego nie drukuje. Dzieje się tak, ponieważ jedna osoba ma baterie, a druga ma latarkę, która zapobiega włączeniu latarki, powodując impas.
Ten przykład jest podobny do przykładu podanego w samouczkach Java: http://docs.oracle.com/javase/tutorial/essential/concurrency/deadlock.html
Innym przykładem jest przykład pętli:
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();
}
}
Ten przykład może albo drukować w kółko „Nieskończone”, albo w ogóle nie może drukować „Nieukończone”. Pierwsza ma miejsce, ponieważ pierwszy wątek uzyskuje blokadę klasy i nigdy jej nie zwalnia, uniemożliwiając dostęp do „stopLoop” przez drugi wątek. A ostatnia ma miejsce, ponieważ drugi wątek rozpoczął się przed pierwszym wątkiem, powodując, że zmienna „done” ma wartość true przed wykonaniem pierwszego wątku.