Verwenden Sie Wait () und benachrichtigen (), um die Zusammenarbeit zwischen den Threads zu erreichen
1.. Wait () und notify ()/notifyall ()
Wenn Sleep () und Rendite () aufgerufen werden, wird das Schloss nicht freigegeben, und das Aufrufen von Wait () wird das Schloss freigeben. Auf diese Weise kann eine andere Aufgabe (Thread) die Sperre des aktuellen Objekts erhalten und so seine synchronisierte Methode eingeben. Sie können die Ausführung von Wait () durch notify ()/notifyall () oder die Zeit abläuft.
Wait (), Notify () und NotifyAll () können nur in der Synchronisationssteuermethode oder im Synchronisationsblock aufgerufen werden. Wenn diese Methoden in einer asynchronen Methode aufgerufen werden, wird eine illegaleMonitorStateException -Ausnahme zur Laufzeit ausgelöst.
2. Simulieren Sie das Aufwachen mehrerer Threads durch einen einzelnen Thread
Simulieren Sie die Zusammenarbeit zwischen Threads. Die Spielklasse verfügt über 2 Synchronisierungsmethoden PREPET () und GO (). Der Flag -Start wird verwendet, um festzustellen, ob der aktuelle Thread warten (). Die Instanz der Spielklasse startet zuerst alle Athele -Klasse -Instanzen und geben Sie den Wait () -Staat ein. Ändern Sie nach einer Zeitspanne das Flaggenbit und notifyall () alle Athele -Fäden im Wartezustand.
Game.java
Paket Parallelität; Import Java.util.Collection; Import Java.util.Collections; Import Java.util.hashset; Import Java.util.iterator; Import Java.util.set; Klasse Athlete Implements Runnable {private endgültige Int id; privates Spiele; Public Athlet (int id, game game) {this.id = id; this.game = game; } public boolean Equals (Objekt o) {if (! (O Instanzsportler)) Return Falsch; Athlet Athlet = (Athlet) o; return id == athlet.id; } public String toString () {return "Athlete <" + id + ">"; } public int hashCode () {neu integer zurückgeben (id) .hashCode (); } public void run () {try {game.prepare (this); } catch (InterruptedException e) {System.out.println (this + "das Spiel beenden"); }}} public Class -Spiel implementiert Runnable {privat set <Portler> player = new Hashset <Portler> (); privater boolescher Start = falsch; public void addPlayer (Athlete eins) {Player.Add (eins); } public void remePlayer (Athlete eins) {Player.Remove (eins); } public collection <Portler> getPlayers () {return collections.unmodifiAbleset (Spieler); } public void prepe (Athlet Athlet) löst InterruptedException aus {System.out.println (Athlet + "Ready!"); synchronisiert (this) {while (! start) wait (); if (start) system.out.println (Athlet + "Go!"); }} public synchronisierte void go () {notifyAll (); } public void Ready () {Iterator <Portler> iter = getPlayers (). iterator (); while (iter.hasnext ()) neuer Thread (iter.Next ()). start (); } public void run () {start = false; System.out.println ("Ready ..."); System.out.println ("Ready ..."); System.out.println ("Ready ..."); bereit(); start = true; System.out.println ("Go!"); gehen(); } public static void main (String [] args) {game game = new Game (); für (int i = 0; i <10; i ++) game.addPlayer (neuer Athlet (i, game)); neuer Thread (Spiel) .Start (); }} Ergebnis:
Bereit ... Bereit ... bereit ... Athlete <0> Bereit! Athlete <1> Bereit! Athlet <2> Bereit! Athlet <3> Bereit! Athlet <4> Bereit! Athlet <5> Bereit! Athlet <6> Bereit! Athlet <7> Bereit! Go! Athlet <3> Geh! Athlet <2> Go! Athlet <1> Geh! Athlet <0> Geh!
3. Simulieren Sie den geschäftigen Wartenprozess
Eine Instanz der MyObject -Klasse ist der Beobachter. Wenn ein Beobachtungsereignis auftritt, informiert es eine Instanz der Monitorklasse (so wie es ist, ein Flag zu ändern). Die Instanz dieser Monitorklasse überprüft ständig, ob sich das Flag -Bit durch Warten ändert.
Tousywaiting.java
import Java.util.concurrent public MyObject (Monitor) {this.Monitor = monitor; } public void run () {try {TimeUnit.seconds.sleep (3); System.out.println ("Ich gehe."); Monitor.gotMessage (); } catch (interruptedException e) {e.printstacktrace (); }}} Klassenmonitor implementiert runnable {private volatile boolean go = false; public void gotMessage () löst InterruptedException {go = true aus; } public void watch () {while (go == false); System.out.println ("Er ist gegangen"); } public void run () {watch (); }} public class touswaiting {public static void main (String [] args) {monitor = new monitor (); MyObject o = new MyObject (Monitor); neuer Thread (o) .Start (); neuer Thread (Monitor) .Start (); }} Ergebnis:
Ich gehe. Er ist gegangen.
V.
Das folgende Beispiel ersetzt den geschäftigen Wartezeitmechanismus durch Wait (). Wenn eine Benachrichtigungsmeldung empfangen wird, benachrichtigen Sie den aktuellen Monitor -Klassen -Thread.
Warte.java
Package Concurrency.wait; import Java.util.Concurrent public MyObject (Monitor) {this.Monitor = monitor; } Starten Sie den Thread regelmäßig
Hier sind zwei Möglichkeiten, um nach einer bestimmten Zeit einen Thread zu starten. Erstens wird es durch java.util.concurrent.delayqueue implementiert; Zweitens wird es durch java.util.concurrent.ScheduledThreadpoolexecutor implementiert.
1. Java.util.Concurrent.DelayQueue
Die Klassenverzögerung ist eine unbegrenzte blockierende Warteschlange, aus der Elemente nur dann extrahiert werden können, wenn die Verzögerung abläuft. Es akzeptiert Instanzen, die die verzögerte Schnittstelle als Elemente implementieren.
<< Schnittstelle >> Delayed.java
Paket java.util.concurrent; import Java.util.*; Public Interface Delayed erweitert vergleichbar <verzögert> {Long getDelay (TimeUnit Unit);}getDelay () gibt die verbleibende Verzögerungszeit zurück, die diesem Objekt zugeordnet ist, die in bestimmten Zeiteinheiten ausgedrückt wird. Die Implementierung dieser Schnittstelle muss eine Vergleichsmethode definieren, die eine konsistente Sortierung mit der GetDelay -Methode dieser Schnittstelle liefert.
Der Kopf der Verzögerungswarteschlange ist das verzögerte Element mit der längsten Speicherzeit nach Ablauf der Verzögerung. Ablauf tritt auf, wenn die Methode GetDelay (TimeUnit.Nanoseconds) eines Elements einen Wert weniger als oder gleich 0 zurückgibt.
2. Design -Warteschlangen mit Zeitverzögerungseigenschaften
Die Klasse DelayedTasker behält eine Delayqueue <vertasttask> -Tit bei, wobei DelayedTask die verzögerte Schnittstelle implementiert und von einer internen Klasse definiert wird. Sowohl externe Klassen als auch interne Klassen implementieren die Runnable -Schnittstelle. Für externe Klassen nimmt seine Run -Methode nach der definierten Zeit die Aufgaben in der Warteschlange aus, und diese Aufgaben sind Instanzen interner Klassen. Die Auslaufmethode der internen Klassen definiert die spezifische Logik jedes Threads.
Die Essenz dieses Designs besteht darin, eine Liste von Threadaufgaben mit Zeitmerkmalen zu definieren, und die Liste kann in jeder Länge sein. Geben Sie bei jedem Hinzufügen einer Aufgabe die Startzeit an.
DelayedTasker.java
Paket com.zj.timedtask; import static java.util.concurrent java.util.concurrent.delayed; import java.util.concurrent public void addtask (delayedTask e) {queue.put (e); } public void removeTask () {queue.poll (); } public collection <vertasttask> getAllTasks () {return collections.unmodifiableCollection (Warteschlange); } 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 ("fertig DelayedTask"); } public statische Klasse DelayedTask implementiert verzögerte, runnable {private static int counter = 0; private endgültige int id = counter ++; Private Final INT Delta; privater endgültiger Auslöser; public DelayedTask (int del DelyInseconds) {Delta = DelyInseconds; Trigger = system.nanotime () + nanoseconds.convert (Delta, Sekunden); } public Long getDelay (ZeitUnit Unit) {return Unit.Convert (Trigger - System.nanotime (), Nanosekunden); } public int vergleicheto (verzögert arg) {delayedTask that = (delayedTask) arg; if (Trigger <that.trigger) return -1; if (Trigger> that.trigger) return 1; Rückkehr 0; } public void run () {// Führen Sie alles aus, was Sie tun möchten. } public String toString () {return "[" + delta + "s]" + "task" + id; }} public static void main (String [] args) {random rand = new random (); ExecutorService Exec = Executors.NewCachedThreadpool (); DelayedTasker Tasker = new DelyedTasker (); für (int i = 0; i <10; i ++) tasker.addtask (neuer DelayedTask (Rand.Nextint (5))); exec.execute (Tasker); exec.shutdown (); }} Ergebnis:
Aufgabe 1 [0S] Aufgabe 2 [0S] Aufgabe 3 [1S] Aufgabe 6 [2S] Aufgabe 5 [3S] Aufgabe 8 [4S] Aufgabe 0 [4S] Aufgabe 4 [4S] Aufgabe 7 [4S] Aufgabe 9FinedDelayedTask
3.. Java.util.Concurrent
Diese Klasse kann geplant werden, um Aufgaben (Threads) nach einer bestimmten Verzögerung auszuführen oder regelmäßig Aufgaben auszuführen (Wiederholung). Im Konstruktor müssen Sie die Größe des Fadenpools kennen. Die Hauptmethode ist:
[1] Zeitplan
öffentlich geplante Future <?> Zeitplan (Runnable -Befehl, lange Verzögerung, Zeiteinheit)
Erstellt und führt eine einmalige Operation durch, die nach einer bestimmten Verzögerung aktiviert ist.
Bezeichnet von:
- Zeitplan in der Schnittstelle enderExecutorService;
Parameter:
-Command - Die aufgenommene Aufgabe;
-Delay - die Zeit, um die Ausführung von nun an zu verzögern;
-Unit - Die Zeiteinheit der Verzögerungsparameter;
zurückkehren:
- Gibt an, dass die geplante Future, die die Aufgabe ausnutzt, und ihre Methode get () nach Abschlussnull zurückgibt.
[2] ScheduleatFixedrat
Öffentliche geplante Future <?> ScheduleatFixedRate (
Runnable Command, Long InitieldElay, lange Zeit, Zeiteinheit)
Erstellen und führen Sie einen periodischen Betrieb aus, der erstmals nach einer bestimmten anfänglichen Verzögerung aktiviert ist, wobei die nachfolgenden Operationen einen bestimmten Zeitraum haben. Das heißt, es wird nach InitialdElay beginnen, dann nach Initialdelay + Periode, dann nach Initialdelay + 2 * Periode usw. Wenn eine Ausführung einer Aufgabe auf eine Ausnahme auftritt, wird die anschließende Ausführung storniert. Andernfalls kann die Aufgabe nur durch Ausführung der Abbrechen- oder Beendigung des Programms beendet werden. Wenn eine der Hinrichtungen dieser Aufgabe länger als der Zyklus dauert, wird die anschließende Ausführung verschoben, jedoch nicht gleichzeitig.
Bezeichnet von:
- ScheduleatFixedrat in der Schnittstelle plandexecutorService;
Parameter:
-Command - Die aufgenommene Aufgabe;
-initialdelay - Die Verzögerungszeit für die erste Ausführung;
-Period - Die Zeit zwischen kontinuierlichen Hinrichtungen;
-Unit - Die Zeiteinheit von InitialdElay und Periodenparametern;
zurückkehren:
- Zeigt an, dass die geplante Future der suspendierten Aufgabe abgeschlossen ist, und die Get () -Methode bringt eine Ausnahme, nachdem sie storniert wurde.
4. Design -Thread -Manager mit Zeitverzögerungseigenschaften
Die Klassenplanung assoziiert einen geplanten Threadpoolexcutor, der die Größe des Thread -Pools angeben kann. Kennen Sie den Thread und die Verzögerungszeit über die Zeitplanmethode und schließen Sie den Thread -Pool über die Shutdown -Methode. Die Logik spezifischer Aufgaben (Threads) hat eine gewisse Flexibilität (im Vergleich zum vorherigen Design muss das vorherige Design die Logik des Threads im Voraus definieren, aber das spezifische Logikdesign des Threads kann durch Vererbung oder Dekoration geändert werden).
Scheduletasker.java
Paket com.zj.timedtask; import java.util.concurrent ScheduledThreadpoolexecutor Scheduler; public Scheduletasker () {Scheduler = new ScheduledThreadpoolexecutor (corepoolSize); } public Scheduletasker (int Menge) {corepoolSize = Menge; Scheduler = new ScheduledThreadpoolexecutor (CorePoolSize); } public void -Zeitplan (Runnable -Ereignis, lange Verzögerung) {Scheduler.Schedule (Ereignis, Verzögerung, Zeitunit.seconds); } public void stilldown () {planuler.shutdown (); } public static void main (String [] args) {Scheduletasker Tasker = new PlanTasker (); Tasker.Schedule (new Runnable () {public void run () {System.out.println ("[1S] Aufgabe 1");}}, 1); Tasker.Schedule (new Runnable () {public void run () {System.out.println ("[2S] Aufgabe 2");}}, 2); Tasker.Schedule (new Runnable () {public void run () {System.out.println ("[4S] Aufgabe 3");}}, 4); Tasker.Schedule (new Runnable () {public void run () {public void run () {System.out.println ("[10S] Aufgabe 4");}}, 10); Tasker.Shutdown (); }} Ergebnis:
[1S] Aufgabe 1 [2S] Aufgabe 2 [4S] Aufgabe 3 [10S] Aufgabe 4 public void run () {try {timeUnit.seconds.sleep (3); System.out.println ("Ich gehe."); Monitor.gotMessage (); } catch (interruptedException e) {e.printstacktrace (); }}} Class Monitor implementiert runnable {private volatile boolean go = false; public synchronisierte void gotMessage () löst unterbrochene Ausnahme {go = true; benachrichtigen(); } public synchronisierte void watch () löst unterbrochene Ausnahme {while (go == false) wait (); System.out.println ("Er ist gegangen"); } public void run () {try {watch (); } catch (interruptedException e) {e.printstacktrace (); }}} public class wait {public static void main (String [] args) {monitor monitor = new Monitor (); MyObject o = new MyObject (Monitor); neuer Thread (o) .Start (); neuer Thread (Monitor) .Start (); }} Ergebnis:
Ich gehe. Er ist gegangen.