Ein Produzent ist ein Thread, der Daten erstellt, und ein Consumer ist ein Thread, der Daten verwendet. Wenn der Produzent und der Konsument als separate Threads arbeiten, wird der Unterschied in der Verarbeitungsgeschwindigkeit zwischen den beiden zu einem Problem. ** Die Daten wurden noch nicht erstellt, wenn der Verbraucher versucht, die Daten zu empfangen, oder der Verbraucher ist nicht bereit, die Daten zu empfangen, wenn der Hersteller versucht, die Daten weiterzugeben **. Im Produzenten-Konsumenten-Muster gibt es eine "Brücke" zwischen Produzenten und Konsumenten. Diese Brücke füllt die Lücke in der Verarbeitungsgeschwindigkeit zwischen den Threads. Wenn sowohl der Produzent als auch der Konsument Singular sind, wird dies manchmal als ** Rohrmuster ** bezeichnet.
Stellen Sie sich ein Beispiel vor, bei dem drei Köche einen Kuchen herstellen und auf den Tisch legen, drei Kunden ihn essen und bis zu drei Kuchen auf den Tisch gelegt werden können. Wenn drei Kuchen auf dem Tisch liegen und der Hahn versucht, mehr Kuchen auf den Tisch zu legen, wartet der Hahn, bis Platz ist, um ihn auf den Tisch zu legen. Wenn ein Kunde versucht, einen Kuchen vom Tisch zu nehmen, während kein Kuchen auf den Tisch gelegt wird, muss der Kunde warten, bis der Kuchen platziert ist.
(Den gesamten Code finden Sie in diesem Handbuch.)
MakerThread
public class MakerThread extends Thread {
...
private static int id = 0; //ƒ Kuchen Seriennummer(Allen Schwänzen gemeinsam)
...
public void run() {
try {
while (true) {
Thread.sleep(random.nextInt(1000));
String cake = "[ Cake No." + nextId() + " by " + getName() + " ]";
table.put(cake);
}
} catch (InterruptedException e) {
}
}
private static synchronized int nextId() {
return id++;
}
}
EaterThread
public class EaterThread extends Thread {
...
public void run() {
try {
while (true) {
String cake = table.take();
Thread.sleep(random.nextInt(1000));
}
} catch (InterruptedException e) {
}
}
...
Table
public class Table {
private final String[] buffer;
private int tail; //Wo als nächstes zu setzen
private int head; //Nächster Ort zu nehmen
private int count; //Anzahl der Kuchen im Puffer
...
//Legen Sie den Kuchen
public synchronized void put(String cake) throws InterruptedException {
System.out.println(Thread.currentThread().getName() + " puts " + cake);
while (count >= buffer.length) {
wait();
}
buffer[tail] = cake;
tail = (tail + 1) % buffer.length;
count++;
notifyAll();
}
//Nimm den Kuchen
public synchronized String take() throws InterruptedException {
while (count <= 0) {
wait();
}
String cake = buffer[head];
head = (head + 1) % buffer.length;
count--;
notifyAll();
System.out.println(Thread.currentThread().getName() + " takes " + cake);
return cake;
}
}
Ausführungsergebnis
...
MakerThread-1 puts [ Cake No.10 by MakerThread-1 ]
EaterThread-1 takes [ Cake No.10 by MakerThread-1 ]
MakerThread-1 puts [ Cake No.11 by MakerThread-1 ]
EaterThread-3 takes [ Cake No.11 by MakerThread-1 ]
MakerThread-3 puts [ Cake No.12 by MakerThread-3 ]
MakerThread-3 puts [ Cake No.13 by MakerThread-3 ]
EaterThread-2 takes [ Cake No.12 by MakerThread-3 ]
EaterThread-3 takes [ Cake No.13 by MakerThread-3 ]
...
Datenrolle: Erstellt von der Producer-Rolle und verwendet von der Consumer-Rolle. Im obigen Beispiel ist dies der Kuchen. Produzentenrolle: Erstellen Sie eine Datenrolle und übergeben Sie sie an die Channel-Rolle. Im obigen Beispiel ist dies die MakerThread-Klasse. Verbraucherrolle: Empfangen Sie die Datenrolle von der Kanalrolle und verwenden Sie sie. Im obigen Beispiel ist dies die EaterThread-Klasse. Kanalrolle: Empfängt die Datenrolle von der Producer-Rolle, speichert sie und übergibt die Data-Rolle als Antwort auf eine Anforderung von der Consumer-Rolle. Die exklusive Kontrolle wird für den Zugriff von der Produzentenrolle und der Konsumentenrolle durchgeführt. Die Channel-Rolle befindet sich zwischen der Producer-Rolle und der Consumer-Rolle und spielt die Rolle eines Relay-Points und eines Kommunikationspfads zum Übergeben der Data-Rolle. Im obigen Beispiel ist dies die Table-Klasse.
Selbst wenn der Thread mit Wartezeit wartet, kann er auf die gleiche Weise wie der Ruhezustand abgebrochen werden. Sie können die Interrupt-Methode verwenden, um dem wartenden Thread mitzuteilen: "Sie müssen nicht mehr auf notify / notifyAll warten. Verlassen Sie das Warteset." Im Falle eines Wartens müssen Sie jedoch beim Sperren vorsichtig sein. Der Faden hatte die Verriegelung einmal gelöst, als er in das eingestellte Gewicht eintrat. Der Thread, der während des Wartens als Interrupt bezeichnet wurde (dh der abgebrochene Thread), gewinnt die Sperre zurück und löst dann eine InterruptedException aus. Das heißt, ** Sie können die Ausnahme InterruptedException erst auslösen, wenn die Sperre aufgehoben ist **.
Beziehung Zusammenfassung der in Java-Sprache erlernten Entwurfsmuster (Multi-Thread-Edition) "(Teil 1) Zusammenfassung der in Java-Sprache erlernten Entwurfsmuster (Multithreaded Edition) "(Teil 2) Zusammenfassung der in Java-Sprache erlernten Entwurfsmuster (Multi-Thread-Edition) "(Teil 3) Zusammenfassung der in Java-Sprache erlernten Entwurfsmuster (Multi-Thread-Edition) "(Teil 4) Zusammenfassung der in Java-Sprache erlernten Entwurfsmuster (Multithread Edition) "(Teil 5) Zusammenfassung der in Java-Sprache erlernten Entwurfsmuster (Multithread Edition) "(Teil 6)
Recommended Posts