travailleur signifie «travailleur». Dans le modèle WorkerThread, les ** threads de travail ** se mettent au travail un par un et le traitent. S'il n'y a pas de travail, le thread de travail attend un nouveau travail. Le thread de travail est parfois appelé ** Thread d'arrière-plan **.
Prenons l'exemple suivant. Un thread de la classe ClientThread envoie une demande de travail à la classe Channel. Une instance de la classe Channel a cinq threads de travail. Le thread de travail attend une demande de travail. Lorsqu'une demande de travail arrive, le thread de travail reçoit une demande de travail de Channel et la traite. Lorsque le processus est terminé, le thread de travail retourne à Channel et attend la demande suivante.
(Voir ce manuel pour le code complet)
Main.java
public class Main {
public static void main(String[] args) {
Channel channel = new Channel(5); //Créer 5 threads de travail
channel.startWorkers(); //Démarrer un thread de travail
new ClientThread("Alice", channel).start(); //Démarrer un thread pour faire une demande de travail
new ClientThread("Bobby", channel).start();
new ClientThread("Chris", channel).start();
}
}
ClientThread.java
public class ClientThread extends Thread {
...
public void run() {
try {
for (int i = 0; true; i++) {
Request request = new Request(getName(), i);
channel.putRequest(request); //Faire une demande d'emploi
Thread.sleep(random.nextInt(1000));
}
} catch (InterruptedException e) {
}
}
}
Channel.java
public class Channel {
private static final int MAX_REQUEST = 100;
private final Request[] requestQueue;
private int tail;
private int head;
private int count;
private final WorkerThread[] threadPool;
public Channel(int threads) {
this.requestQueue = new Request[MAX_REQUEST];
this.head = 0;
this.tail = 0;
this.count = 0;
threadPool = new WorkerThread[threads];
for (int i = 0; i < threadPool.length; i++) {
threadPool[i] = new WorkerThread("Worker-" + i, this);
}
}
public void startWorkers() {
for (int i = 0; i < threadPool.length; i++) {
threadPool[i].start();
}
}
public synchronized void putRequest(Request request) {
while (count >= requestQueue.length) {
try {
wait();
} catch (InterruptedException e) {
}
}
requestQueue[tail] = request;
tail = (tail + 1) % requestQueue.length;
count++;
notifyAll();
}
public synchronized Request takeRequest() {
while (count <= 0) {
try {
wait();
} catch (InterruptedException e) {
}
}
Request request = requestQueue[head];
head = (head + 1) % requestQueue.length;
count--;
notifyAll();
return request;
}
}
WorkerThread.java
public class WorkerThread extends Thread {
...
public void run() {
while (true) {
Request request = channel.takeRequest(); //Va chercher un travail
request.execute();
}
}
}
La classe Channel a un champ appelé requestQueue pour transmettre les demandes de travail. La méthode putRequest place une requête dans cette file d'attente et la méthode takeRequest la récupère. Ici, le modèle producteur-consommateur est utilisé. Le modèle Thread-Per-Message a engendré un nouveau thread à chaque fois qu'il a fait un travail. Toutefois, dans le modèle de thread de travail, ** les threads de travail exécutent le travail à plusieurs reprises, il n'est donc pas nécessaire de démarrer un nouveau thread. ** WorkerThread n'a qu'une instance de Channel pour obtenir une demande de travail, et ne sait rien du travail spécifique.
Rôle du client Le rôle Client crée une demande de travail en tant que rôle Request et la transmet au rôle Channel. Dans l'exemple de programme, la classe ClientThread a joué ce rôle.
Rôle du canal Le rôle Channel reçoit le rôle Request du rôle Client et le transmet au rôle Worker. Dans l'exemple de programme, la classe Channel a joué ce rôle.
Rôle du travailleur Le rôle Worker reçoit le rôle Request du rôle Channel et exécute le travail. Après le travail, accédez au prochain rôle Request. Dans l'exemple de programme, la classe WorkerThread a joué ce rôle.
Demander un rôle Le rôle Request est de représenter un travail. Le rôle Request contient les informations nécessaires pour exécuter la tâche. Dans l'exemple de programme, la classe Request a joué ce rôle.
Augmentation du débit Contrairement au modèle Thread-Per-Message, le modèle Worker Thread a l'un des thèmes de ** réutilisation des threads et de recyclage pour augmenter le débit **.
Contrôle de capacité La quantité de services qui peuvent être fournis en même temps est appelée capacité. Le nombre de rôles de travail peut être librement déterminé. Dans l'exemple de programme, il s'agit des threads d'argument donnés au constructeur Channel. Plus vous avez de rôles de travail, plus vous pouvez effectuer de travail en parallèle, mais préparer plus de rôles de travail que le nombre de travaux demandés en même temps est inutile et consomme plus de ressources. Le nombre de rôles de travail ne doit pas nécessairement être défini au démarrage et peut être modifié de manière dynamique. Le rôle Channel détient le rôle Request. Si le nombre de rôles de demande pouvant être détenus par le rôle de canal est important, la différence de vitesse de traitement entre le rôle de client et le rôle de travail peut être remplie (mise en mémoire tampon). Cependant, une grande quantité de mémoire est consommée pour contenir le rôle Request. Vous pouvez voir qu'il y a un ** compromis capacité-ressources ** ici.
Séparation de l'invocation et de l'exécution Lors d'un appel de méthode normal, "l'invocation de méthode" et "l'exécution de méthode" sont exécutées successivement. ** Dans un appel de méthode normal, l'invocation et l'exécution sont inséparables **. Cependant, ** les modèles de thread de travail et les modèles de thread par message séparent l'appel et l'exécution de la méthode **. L'appel d'une méthode est appelé invocation et l'exécution est appelée exécution. ** On peut dire que le modèle Worker Thread et le modèle Thread-Per-Message séparent l'appel et l'exécution d'une méthode **. Cela présente les avantages suivants.
--Contrôle de l'ordre d'exécution (ordonnancement) Vous pouvez hiérarchiser le rôle Request et contrôler l'ordre dans lequel le rôle Channgel passe le rôle Request au rôle Worker. C'est ce qu'on appelle la demande ** planification **.
--Annulable / Répétable Bien que l'appel ait été effectué, l'exécution peut réaliser une fonction appelée annulation.
--Traitement distribué Il devient plus facile de séparer l'ordinateur à appeler et l'ordinateur à exécuter.
Rôle de requête à multiples facettes Par exemple, si vous créez une sous-classe de la classe Request et passez son instance à Channel, WorkerThread appellera execute pour cette instance sans aucun problème. Cela peut être exprimé comme utilisant le ** polymorphisme **. Étant donné que toutes les informations nécessaires pour exécuter le travail sont décrites dans le rôle de demande, même si un rôle de demande à multiples facettes est créé et que les types de travail sont augmentés, le rôle de canal et le rôle de travailleur n'ont pas besoin de le modifier. Même si le nombre de types de travail augmente, le rôle Worker n'appelle toujours que la méthode d'exécution du rôle Request.
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 multithread)» (Partie 6) Résumé de «Modèles de conception appris en langage Java (édition multithread)» (Partie 7) Résumé de «Modèles de conception appris en langage Java (édition multi-thread)» (Partie 8) Résumé de «Modèles de conception appris en langage Java (édition multi-thread)» (Partie 9)
Recommended Posts