Un producteur est un thread qui crée des données et un consommateur est un thread qui utilise des données. Lorsque le producteur et le consommateur fonctionnent comme des threads séparés, la différence de vitesse de traitement entre les deux devient un problème. ** Les données n'ont pas encore été créées lorsque le consommateur tente de recevoir les données, ou le consommateur n'est pas prêt à recevoir les données lorsque le producteur tente de transmettre les données **. Dans le modèle producteur-consommateur, il existe un «pont» entre les producteurs et les consommateurs. Ce pont comble le vide dans la vitesse de traitement entre les threads. Lorsque le producteur et le consommateur sont tous deux singuliers, on l'appelle parfois le ** modèle de tuyau **.
Prenons un exemple où trois cuisiniers font un gâteau et le mettent sur la table, trois clients le mangent et jusqu'à trois gâteaux peuvent être mis sur la table. S'il y a trois gâteaux sur la table et que le coq essaie de mettre plus de gâteaux sur la table, le coq attend qu'il y ait de la place pour le mettre sur la table. Si un client essaie de prendre un gâteau de la table alors qu'aucun gâteau n'est posé sur la table, le client devra attendre que le gâteau soit placé.
(Voir ce manuel pour le code complet)
MakerThread
public class MakerThread extends Thread {
...
private static int id = 0; //ƒ Numéro de série du gâteau(Commun à tous les coqs)
...
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; //Où mettre ensuite
private int head; //Prochain endroit à prendre
private int count; //Nombre de gâteaux dans le tampon
...
//Mettez le gâteau
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();
}
//Prendre le gâteau
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;
}
}
Résultat d'exécution
...
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 ]
...
Rôle des données: Créé par le rôle Producteur et utilisé par le rôle Consumer. Dans l'exemple ci-dessus, c'est le gâteau. Rôle du producteur: Créez un rôle Data et transmettez-le au rôle Channel. Dans l'exemple ci-dessus, il s'agit de la classe MakerThread. Rôle du consommateur: Recevez le rôle Data du rôle Channel et utilisez-le. Dans l'exemple ci-dessus, il s'agit de la classe EaterThread. Rôle du canal: Reçoit le rôle Data du rôle Producer, le stocke et transmet le rôle Data en réponse à une demande du rôle Consumer. Un contrôle exclusif est effectué pour l'accès depuis le rôle Producteur et le rôle Consommateur. Le rôle Channel se situe entre le rôle Producer et le rôle Consumer, et joue le rôle d'un point relais et d'un chemin de communication pour transmettre le rôle Data. Dans l'exemple ci-dessus, il s'agit de la classe Table.
Même si le thread attend avec wait, il peut être annulé de la même manière que sleep. Vous pouvez utiliser la méthode d'interruption pour dire au thread en attente: «Vous n'avez plus à attendre notifier / notifierAll. Sortez de l'attente». Cependant, en cas d'attente, vous devez faire attention au verrouillage. Le fil avait relâché le verrou une fois lorsqu'il est entré dans le jeu de poids. Le thread qui a été appelé interruption pendant l'attente (c'est-à-dire le thread qui a été annulé) récupère le verrou, puis lève une InterruptedException. Autrement dit, vous ne pouvez pas lever d'exception InterruptedException tant que ** le verrou n'est pas pris **.
Relation Résumé de «Modèles de conception appris en langage Java (édition multithread)» (Partie 1) Résumé de "Modèles de conception appris en langage Java (édition multithread)" (Partie 2) Résumé de «Modèles de conception appris en langage Java (édition multithread)» (Partie 3) Résumé de «Modèles de conception appris en langage Java (édition multi-thread)» (Partie 4) Résumé de «Modèles de conception appris en langage Java (édition multithread)» (Partie 5) Résumé de «Modèles de conception appris en langage Java (édition multi-thread)» (Partie 6)
Recommended Posts