Da keine Antwort als akzeptierte Antwort markiert ist, habe ich versucht, ein Beispiel für eine Live-Sperre zu erstellen.
Das ursprüngliche Programm wurde von mir im April 2012 geschrieben, um verschiedene Konzepte des Multithreading zu erlernen. Dieses Mal habe ich es geändert, um Deadlock, Race Condition, Livelock usw. zu erstellen.
Lassen Sie uns zuerst die Problemstellung verstehen.
Cookie Maker Problem
Es gibt einige Zutatenbehälter : ChocoPowederContainer , WheatPowderContainer . CookieMaker entnimmt etwas Pulver aus Zutatenbehältern , um ein Cookie zu backen . Wenn ein Cookie-Hersteller feststellt, dass ein Container leer ist, sucht er nach einem anderen Container, um Zeit zu sparen. Und wartet, bis Filler den gewünschten Behälter füllt. Es gibt einen Füllstoff, der den Behälter in regelmäßigen Abständen überprüft und eine bestimmte Menge füllt, wenn ein Behälter dies benötigt.
Bitte überprüfen Sie den vollständigen Code auf Github ;
Lassen Sie mich die Implementierung kurz erläutern.
- Ich starte Filler als Daemon-Thread. So werden die Behälter in regelmäßigen Abständen gefüllt. Um einen Behälter zuerst zu füllen, verschließt er den Behälter -> prüft, ob er etwas Pulver benötigt -> füllt ihn -> signalisiert allen Herstellern, die darauf warten -> entsperrt den Behälter.
- Ich erstelle CookieMaker und stelle ein, dass es bis zu 8 Cookies parallel backen kann. Und ich starte 8 Threads, um Kekse zu backen.
- Jeder Maker-Thread erstellt 2 aufrufbare Unter-Threads, um Pulver aus Behältern zu entnehmen.
- Der Unterfaden verriegelt einen Behälter und prüft, ob genügend Pulver vorhanden ist. Wenn nicht, warten Sie einige Zeit. Sobald der Füllstoff den Behälter füllt, nimmt er das Pulver und entriegelt den Behälter.
- Jetzt werden andere Aktivitäten abgeschlossen, z. B. Mischen und Backen usw.
Werfen wir einen Blick in den Code:
CookieMaker.java
private Integer getMaterial(final Ingredient ingredient) throws Exception{
:
container.lock();
while (!container.getIngredient(quantity)) {
container.empty.await(1000, TimeUnit.MILLISECONDS);
//Thread.sleep(500); //For deadlock
}
container.unlock();
:
}
IngredientContainer.java
public boolean getIngredient(int n) throws Exception {
:
lock();
if (quantityHeld >= n) {
TimeUnit.SECONDS.sleep(2);
quantityHeld -= n;
unlock();
return true;
}
unlock();
return false;
}
Alles läuft gut, bis Filler die Behälter füllt. Wenn ich jedoch vergesse, den Füllstoff zu starten, oder der Füllstoff unerwartet verlassen wird, ändern die Sub-Threads ständig ihren Status, damit andere Hersteller den Behälter überprüfen können.
Ich habe auch einen Daemon- ThreadTracer erstellt, der Thread-Zustände und Deadlocks überwacht. Dies ist die Ausgabe von der Konsole;
2016-09-12 21:31:45.065 :: [Maker_0:WAITING, Maker_1:WAITING, Maker_2:WAITING, Maker_3:WAITING, Maker_4:WAITING, Maker_5:WAITING, Maker_6:WAITING, Maker_7:WAITING, pool-7-thread-1:TIMED_WAITING, pool-7-thread-2:TIMED_WAITING, pool-8-thread-1:TIMED_WAITING, pool-8-thread-2:TIMED_WAITING, pool-6-thread-1:TIMED_WAITING, pool-6-thread-2:TIMED_WAITING, pool-5-thread-1:TIMED_WAITING, pool-5-thread-2:TIMED_WAITING, pool-1-thread-1:TIMED_WAITING, pool-3-thread-1:TIMED_WAITING, pool-2-thread-1:TIMED_WAITING, pool-1-thread-2:TIMED_WAITING, pool-4-thread-1:TIMED_WAITING, pool-4-thread-2:RUNNABLE, pool-3-thread-2:TIMED_WAITING, pool-2-thread-2:TIMED_WAITING]
2016-09-12 21:31:45.065 :: [Maker_0:WAITING, Maker_1:WAITING, Maker_2:WAITING, Maker_3:WAITING, Maker_4:WAITING, Maker_5:WAITING, Maker_6:WAITING, Maker_7:WAITING, pool-7-thread-1:TIMED_WAITING, pool-7-thread-2:TIMED_WAITING, pool-8-thread-1:TIMED_WAITING, pool-8-thread-2:TIMED_WAITING, pool-6-thread-1:TIMED_WAITING, pool-6-thread-2:TIMED_WAITING, pool-5-thread-1:TIMED_WAITING, pool-5-thread-2:TIMED_WAITING, pool-1-thread-1:TIMED_WAITING, pool-3-thread-1:TIMED_WAITING, pool-2-thread-1:TIMED_WAITING, pool-1-thread-2:TIMED_WAITING, pool-4-thread-1:TIMED_WAITING, pool-4-thread-2:TIMED_WAITING, pool-3-thread-2:TIMED_WAITING, pool-2-thread-2:TIMED_WAITING]
WheatPowder Container has 0 only.
2016-09-12 21:31:45.082 :: [Maker_0:WAITING, Maker_1:WAITING, Maker_2:WAITING, Maker_3:WAITING, Maker_4:WAITING, Maker_5:WAITING, Maker_6:WAITING, Maker_7:WAITING, pool-7-thread-1:TIMED_WAITING, pool-7-thread-2:TIMED_WAITING, pool-8-thread-1:TIMED_WAITING, pool-8-thread-2:TIMED_WAITING, pool-6-thread-1:TIMED_WAITING, pool-6-thread-2:TIMED_WAITING, pool-5-thread-1:TIMED_WAITING, pool-5-thread-2:TIMED_WAITING, pool-1-thread-1:TIMED_WAITING, pool-3-thread-1:TIMED_WAITING, pool-2-thread-1:TIMED_WAITING, pool-1-thread-2:TIMED_WAITING, pool-4-thread-1:TIMED_WAITING, pool-4-thread-2:TIMED_WAITING, pool-3-thread-2:TIMED_WAITING, pool-2-thread-2:RUNNABLE]
2016-09-12 21:31:45.082 :: [Maker_0:WAITING, Maker_1:WAITING, Maker_2:WAITING, Maker_3:WAITING, Maker_4:WAITING, Maker_5:WAITING, Maker_6:WAITING, Maker_7:WAITING, pool-7-thread-1:TIMED_WAITING, pool-7-thread-2:TIMED_WAITING, pool-8-thread-1:TIMED_WAITING, pool-8-thread-2:TIMED_WAITING, pool-6-thread-1:TIMED_WAITING, pool-6-thread-2:TIMED_WAITING, pool-5-thread-1:TIMED_WAITING, pool-5-thread-2:TIMED_WAITING, pool-1-thread-1:TIMED_WAITING, pool-3-thread-1:TIMED_WAITING, pool-2-thread-1:TIMED_WAITING, pool-1-thread-2:TIMED_WAITING, pool-4-thread-1:TIMED_WAITING, pool-4-thread-2:TIMED_WAITING, pool-3-thread-2:TIMED_WAITING, pool-2-thread-2:TIMED_WAITING]
Sie werden feststellen, dass Sub-Threads und ihre Zustände ändern und warten.