Utilisez wait () et notify () pour réaliser une collaboration inter-thread
1. Wait () et notify () / notifyall ()
Lorsque Sleep () et le rendement () sont appelés, le verrou n'est pas libéré et l'appel Wait () libèrera le verrou. De cette façon, une autre tâche (thread) peut obtenir le verrouillage de l'objet actuel, entrant ainsi sa méthode synchronisée. Vous pouvez reprendre l'exécution de Wait () via notify () / notifyall () ou le temps expire.
Wait (), notify (), et notifyall () ne peut être appelé que dans la méthode de contrôle de synchronisation ou le bloc de synchronisation. Si ces méthodes sont appelées dans une méthode asynchrone, une exception illégalitorstateException sera lancée au moment de l'exécution.
2. Simuler le réveil de plusieurs threads par un seul thread
Simuler la collaboration entre les fils. La classe de jeu a 2 méthodes de synchronisation préparé () et go (). Le démarrage du drapeau est utilisé pour déterminer si le thread actuel doit être attendu (). L'instance de la classe de jeu commence d'abord toutes les instances de classe d'Athele et entrez l'état d'attente (). Après une période de temps, modifiez le bit du drapeau et notifyall () tous les fils d'Athele dans l'état d'attente.
Jeu.java
package concurrencée; import java.util.collection; import java.util.collections; import java.util.hashset; import java.util.iterator; import java.util.set; class athlète implémente runnable {private final int id; jeu privé; Athlète public (int id, jeu de jeu) {this.id = id; this.game = jeu; } public booléen égaux (objet o) {if (! (o instanceof athlète)) return false; Athlète athlète = (athlète) o; RETOUR ID == athlète.id; } public String toString () {return "Athlète <" + id + ">"; } public int hashcode () {return new Integer (id) .hashCode (); } public void run () {try {game.prepare (this); } catch (InterruptedException e) {System.out.println (this + "quit le jeu"); }}} Le jeu de classe publique implémente Runnable {private set <athath> joueurs = new hashset <athath> (); Start booléen privé = false; public void addPlayer (Athlete One) {Players.add (un); } public void removePlayer (Athlete One) {Players.Remove (un); } public Collection <Sthlete> GetPlayers () {return Collection.UnModifiablesEt (joueurs); } public void prépare (athlète athlète) lève InterruptedException {System.out.println (athlète + "Ready!"); synchronisé (this) {while (! start) wait (); if (start) System.out.println (athlète + "Go!"); }} public synchronisé void go () {notifyall (); } public void ready () {iterator <athath>> iter = getPlayers (). iterator (); while (iter.hasnext ()) nouveau thread (iter.next ()). start (); } public void run () {start = false; System.out.println ("Ready ..."); System.out.println ("Ready ..."); System.out.println ("Ready ..."); prêt(); start = true; System.out.println ("Go!"); aller(); } public static void main (string [] args) {game game = new Game (); pour (int i = 0; i <10; i ++) game.addplayer (nouvel athlète (i, jeu)); nouveau thread (jeu) .start (); }} résultat:
Prêt ... prêt ... prêt ... Athlète <0> Prêt! Athlète <1> Ready! Athlète <2> Ready! Athlète <3> Ready! Athlète <4> Ready! Athlete <5> Ready! Athlete <6> Ready! Athlète <7> Ready! Athlète <8> Ready! Athlète <9> Prêt! Go! Athlète <9> Go! Athlète <8> Go! Athlète <7> Go! Allez! Athlète <3> GO! Athlète <2> Go! Athlète <1> GO! Athlète <0> GO!
3. Simuler le processus d'attente occupé
Une instance de la classe MyObject est l'observateur. Lorsqu'un événement d'observation se produit, il informera une instance de la classe Monitor (la façon dont il est de modifier un drapeau). L'instance de cette classe de moniteur vérifie constamment si le bit du drapeau change en attendant.
Busywaiting.java
Importer java.util.concurrent.TimeUnit; class MyObject implémente Runnable {private monitor Monitor; public myObject (Monitor Monitor) {this.monitor = monitor; } public void run () {try {timeunit.seconds.sleep (3); System.out.println ("Je vais."); Monitor.GotMessage (); } catch (InterruptedException e) {e.printStackTrace (); }}} Le moniteur de classe implémente Runnable {private volatile boolean go = false; public void gotMessage () lève InterruptedException {go = true; } public void watching () {while (go == false); System.out.println ("Il est parti."); } public void run () {watching (); }} classe publique BusyWaiting {public static void main (String [] args) {monitor monitor = new monitor (); MyObject o = new MyObject (moniteur); nouveau thread (o) .start (); nouveau thread (moniteur) .start (); }} résultat:
Je vais. Il est parti.
4. Utilisez Wait () et Notify () pour réécrire l'exemple ci-dessus
L'exemple suivant remplace le mécanisme d'attente occupée via Wait (). Lorsqu'un message de notification est reçu, informez le thread de classe de moniteur actuel.
Attendre.java
package concurrency.wait; import java.util.concurrent.TimeUnit; class MyObject implémente Runnable {private Monitor Monitor; public myObject (Monitor Monitor) {this.monitor = monitor; } Démarrez régulièrement le fil
Voici deux façons de démarrer un fil après une heure spécifiée. Tout d'abord, il est mis en œuvre via java.util.concurrent.delayqueue; Deuxièmement, il est implémenté via java.util.concurrent.scheduledThreadPoolExecutor.
1. Java.util.concurrent.delayqueue
La classe de retard est une file d'attente de blocage illimitée à partir de laquelle les éléments ne peuvent être extraits que lorsque le retard expire. Il accepte les instances qui implémentent l'interface retardée en tant qu'éléments.
<< Interface >> retardé.java
package java.util.concurrent; import java.util. *; interface publique retardée étend comparable <layed> {long getdelay (timeunit unit);}getdelay () renvoie le temps de retard restant associé à cet objet, exprimé dans des unités de temps données. L'implémentation de cette interface doit définir une méthode de comparaison qui fournit un tri cohérent avec la méthode GetDelay de cette interface.
La tête de la file d'attente de retard est l'élément retardé avec le temps de stockage le plus long après l'expiration du retard. L'expiration se produit lorsque la méthode Getdelay (timeUnit.Nanoseconds) d'un élément renvoie une valeur inférieure ou égale à 0.
2. Files d'attente de conception avec caractéristiques de retard
La classe DelayedTasker maintient une file d'attente de retard de retard <ladedTask>, où DelayEdTask implémente l'interface retardée et est définie par une classe interne. Les classes externes et les classes internes implémentent l'interface Runnable. Pour les classes externes, sa méthode d'exécution élimine les tâches dans la file d'attente en séquence en fonction du temps défini, et ces tâches sont des instances de classes internes. La méthode d'exécution des classes internes définit la logique spécifique de chaque thread.
L'essence de cette conception est de définir une liste de tâches de fil avec les caractéristiques du temps, et la liste peut être de n'importe quelle longueur. Spécifiez l'heure de démarrage chaque fois que vous ajoutez une tâche.
DelayedTasker.java
package com.zj.timedtask; import static java.util.concurrent.timeunit.seconds; import static java.util.concurrent.timeunit.nanoseconds; importer java.util.collection; import java.util.concurrent.DeLayque. java.util.concurrent.delayed; importer java.util.concurrent.execcutorService; Importer java.util.concurrent.executors; import java.util.concurrent.timeunit; public class delaydTasker implémente Runnable {deladeue <ladedTask> quereue = newrellayleeue <ladedTask>;); public void addTask (DelayedTask e) {queue.put (e); } public void removeTask () {queue.poll (); } COLLECTION PUBLIQUE <LAFKEDTASK> GETALLTASKS () {return Collection.UnModifiBebleCollection (file d'attente); } public int getTaskquantity () {return queue.size (); } public void run () {while (! queue.isempty ()) try {queue.take (). run (); } catch (InterruptedException e) {System.out.println ("Interrupted"); } System.out.println ("fini deltEdTask"); } Classe statique publique DelayEdTask implémente retardé, runnable {private static int compter = 0; private final int id = compter ++; Final privé Int Delta; Triveur long final privé; public DelayEdTask (int delayInseConds) {delta = delayInseConds; Trigger = System.NanoTime () + nanoseConds.Convert (Delta, secondes); } public long getdelay (timeunit unit) {return unit.convert (Trigger - System.NanoTime (), nanosecondes); } public int compareto (retardé arg) {deltEdTask That = (deltEdTask) arg; if (déclencheur <that.trigger) return -1; if (Trigger> that.trigger) return 1; retour 0; } public void run () {// Exécutez tout ce que vous voulez faire System.out.println (this); } public String toString () {return "[" + delta + "s]" + "tâche" + id; }} public static void main (string [] args) {random rand = new random (); ExecutorService exec = exécutor.NewCachedThreadPool (); DelayedTasker Tasker = new DelayEdTasker (); pour (int i = 0; i <10; i ++) tasker.addtask (new DelayedTask (rand.nextint (5))); exec.execute (Tasker); exec.shutdown (); }} résultat:
[0s] Tâche 1 [0s] Tâche 2 [0S] Tâche 3 [1S] Tâche 6 [2S] Tâche 5 [3S] Tâche 8 [4S] Tâche 0 [4S] Tâche 4 [4S] Tâche 7 [4S] Tâche 9FinishedDelayEdTask
3. Java.util.concurrent.ScheduledTheredpoolExecutor
Cette classe peut être planifiée pour exécuter des tâches (threads) après un retard donné ou pour effectuer des tâches régulièrement (répéter). Dans le constructeur, vous devez connaître la taille du pool de fils. La méthode principale est:
[1] Calendrier
Public ScheduledFuture <?> Calendrier (commande Runnable, Long Delay, TimeUnit Unit)
Crée et effectue une opération unique activée après un retard donné.
Désigné par:
- Planification dans l'interface ScheduleDexecutorService;
paramètre:
-Command - La tâche à effectuer;
-Delay - le temps de retarder l'exécution à partir de maintenant;
-Unit - L'unité de temps des paramètres de retard;
retour:
- indique que la transition planifiée qui suspend la tâche et sa méthode get () retournera null après l'achèvement.
[2] ScheduleAtfixeDrate
Public ScheduledFuture <?> ScheduleAtFixeDrate (
Commande Runnable, Long InitialDelay, longue période, unité de timeUnit)
Créer et exécuter une opération périodique qui est d'abord activée après un retard initial donné, les opérations suivantes ayant une période donnée; Autrement dit, il commencera après InitialDelay, puis après InitialDelay + Période, puis après InitialDelay + 2 *, et ainsi de suite. Si une exécution d'une tâche rencontre une exception, l'exécution ultérieure sera annulée. Sinon, la tâche ne peut être résiliée qu'en exécutant la méthode d'annulation ou de résiliation du programme. Si l'une des exécutions de cette tâche prend plus de temps que son cycle, l'exécution ultérieure sera reportée, mais pas simultanément.
Désigné par:
- scheduleAtFixeDrate dans l'interface scheduleExECUTORSService;
paramètre:
-Command - La tâche à effectuer;
-InitialDelay - Le temps de retard pour la première exécution;
-period - la période entre les exécutions continues;
-Unit - L'unité de temps de InitialDelay et les paramètres de période;
retour:
- Indique que la transition prévue de la tâche suspendue est terminée et sa méthode get () lancera une exception après son annulation.
4. Exécuteurs de threads de conception avec caractéristiques de retard
Le calendrier de classe associe un ScheduledThreadPoolExcutor, qui peut spécifier la taille du pool de threads. Connaissez le thread et retardez le temps via la méthode de planification et fermez le pool de threads via la méthode d'arrêt. La logique des tâches spécifiques (threads) a une certaine flexibilité (par rapport à la conception précédente, la conception précédente doit définir la logique du thread à l'avance, mais la conception logique spécifique du thread peut être modifiée par héritage ou décoration).
Scheduletasker.java
package com.zj.timedtask; import java.util.concurrent.scheduledThreadPoolExecutor; Importer java.util.concurrent.TimeUnit; public class scheduletasker {private int corepoolSize = 10; ScheduledThreadPoolExecutor Scheduler; public scheduleTasker () {scheduler = new scheduledTreadPoolExecutor (corePoolSize); } public scheduleTasker (INT Quantity) {CorePoolSize = Quantity; scheduler = new scheduledThreadPoolExecutor (corePoolSize); } Public Void Schedule (événement Runnable, Long Delay) {Scheduler.Schedule (événement, Delay, TimeUnit.seconds); } public void shutdown () {scheduler.shutdown (); } public static void main (String [] args) {scheduleTasker tasker = new scheduleTasker (); tasker.schedule (new Runnable () {public void run () {System.out.println ("[1s] Tâche 1");}}, 1); tasker.schedule (new Runnable () {public void run () {System.out.println ("[2s] tâche 2");}}, 2); tasker.schedule (new runnable () {public void run () {System.out.println ("[4s] tâche 3");}}, 4); tasker.schedule (new Runnable () {public void run () {public void run () {System.out.println ("[10s] tâche 4");}}, 10); tasker.shutdown (); }} résultat:
[1S] Tâche 1 [2S] Tâche 2 [4S] Tâche 3 [10S] Tâche 4 public void run () {try {timeunit.seconds.sleep (3); System.out.println ("Je vais."); Monitor.GotMessage (); } catch (InterruptedException e) {e.printStackTrace (); }}} Le moniteur de classe implémente Runnable {private volatile boolean go = false; public synchronisé void gotMessage () lève InterruptedException {go = true; notify (); } public synchronisé void watching () lève InterruptedException {while (go == false) wait (); System.out.println ("Il est parti."); } public void run () {try {watching (); } catch (InterruptedException e) {e.printStackTrace (); }}} public class wait {public static void main (String [] args) {monitor monitor = new monitor (); MyObject o = new MyObject (moniteur); nouveau thread (o) .start (); nouveau thread (moniteur) .start (); }} résultat:
Je vais. Il est parti.