Thread -Statusdiagramm
Themen enthalten die folgenden 5 Zustände.
1. New State: Nachdem das Thread -Objekt erstellt wurde, tritt er in den neuen Zustand ein. Zum Beispiel thread Thread = neuer Thread ().
2. Ready State (Runnable): Auch als "ausführbarer Zustand" bezeichnet. Nachdem das Thread -Objekt erstellt wurde, rufen andere Threads die Start () -Methode des Objekts auf, um den Thread zu starten. Zum Beispiel thread.start (). Ein Thread in einem fertigen Zustand kann jederzeit von der CPU ausgeführt werden.
3. Auslaufstatus (ausgeführt): Der Thread erhält CPU -Berechtigungen für die Ausführung. Es ist zu beachten, dass Threads nur den laufenden Status aus dem Ready State eingeben können.
4. Blockierter Zustand: Blockierter Zustand bedeutet, dass der Thread die CPU -Nutzungsrechte aus irgendeinem Grund aufgibt und vorübergehend nicht mehr läuft. Erst wenn der Thread in den bereiten Zustand eingeht, hat er die Chance, in den Laufstatus zu gehen. Es gibt drei Arten von Blockaden:
.
(02) Synchronisierte Blockierung-Ein Thread erfasst das synchronisierte Synchronisationsschloss (da das Schloss von anderen Threads besetzt ist), und tritt in einen synchronisierten Blockierungszustand ein.
(03) Andere Blockierungen-Der Thread wird in einen Blockierungsstatus gelangen, indem Sie Schlaf () oder Join () des Threads anrufen oder eine E/A-Anfrage ausstellen. Wenn der Sleep () -State zeitlich abgestimmt war, Join () darauf wartete, dass der Faden endet oder zeitlich abgestimmt hat oder die E/A-Verarbeitung abgeschlossen wurde, wurde der Thread wieder in den bereiten Zustand eingegeben.
5. Dead State: Der Thread hat die Ausführung der Run () -Methode aufgrund einer Ausnahme beendet oder beendet, und der Thread beendet seinen Lebenszyklus.
Implementieren Sie Multi-Threading-Methoden-Thread und Runnable
Thread: Erben Sie die Thread -Klasse, implementieren Sie die Ausführungsmethode und rufen Sie die Startmethode in der Hauptfunktion auf, um den Thread zu starten
Runnable: Schnittstelle, implementiert die Runnable -Schnittstelle, übergibt sie als Parameter an Thread Constructor und ruft die Startmethode im Main auf
Beispiel:
Klassenaufgabe implementiert Runnable {private int Ticket = 10; @Override public void run () {für (int i = 0; i <20; i ++) {if (this.ticket> 0) {System.out.println (Thread.currentThread (). GetName () + "verkauftes Ticket" + this.ticket-); }}}}}}; public class runnabletest {public static void main (string [] args) {task mytask = new Task (); Thread t1 = neuer Thread (mytask); Thread T2 = neuer Thread (mytask); Thread T3 = neuer Thread (mytask); t1.start (); t2.Start (); t3.Start (); }} // threadTest.java Quellcodeklasse MyThread erweitert Thread {private int ticket = 10; public void run () {für (int i = 0; i <20; i ++) {if (this.ticket> 0) {system.out.println (this.getName () + "Ticket verkaufen: Ticket" + this.ticket--); }}}} public class threadtest {public static void main (string [] args) {// starten 3 threads t1, t2, t3; Jeder Thread verkauft jeweils 10 Tickets! MyThread t1 = new MyThread (); MyThread t2 = new MyThread (); MyThread t3 = new MyThread (); t1.start (); t2.Start (); t3.Start (); }};
Der Unterschied zwischen Thread und Runnable
Thread ist eine Klasse, und runnable ist eine Schnittstelle; Thread selbst ist eine Klasse, die die Runnable -Schnittstelle implementiert. Wir wissen, dass "eine Klasse nur eine übergeordnete Klasse haben kann, aber mehrere Schnittstellen implementieren kann", so dass Runnable eine bessere Skalierbarkeit hat. Darüber hinaus kann Runnable auch zum "Austausch von Ressourcen" verwendet werden. Das heißt, mehrere Threads werden basierend auf einem bestimmten Runnable -Objekt erstellt, und sie teilen Ressourcen für das Runnable -Objekt. Im Allgemeinen wird empfohlen, Multi-Threading durch "Runnable" zu implementieren!
Thread's Run and Start
start (): Seine Funktion besteht darin, einen neuen Thread zu starten, und der neue Thread führt die entsprechende Run () -Methode aus. start () kann nicht wiederholt aufgerufen werden. start () startet den Thread tatsächlich über die lokale Methode start0 (). Start0 () wird einen neuen Thread ausgeführt, und der neue Thread ruft die Run () -Methode auf.
run (): run () kann wiederholt genauso wie gewöhnliche Mitgliedsmethoden aufgerufen werden. Wenn Sie Run () getrennt anrufen, wird run () im aktuellen Thread ausgeführt und der neue Thread wird nicht gestartet! Run () wird die Run () -Methode des Runnable -Elements des Thread -Threads direkt aufrufen und erstellt keinen neuen Thread.
// Demo.javas Quellcodeklasse MyThread erweitert Thread {public myThread (String name) {Super (name); } public void run () {System.out.println (Thread.currentThread (). getName ()+"läuft"); }}; public class Demo {public static void main (String [] args) {Thread mythead = new mythead ("mythead"); System.out.println (Thread.currentThread (). GetName ()+"rufen Sie Mythead.run ()"); MyThread.run (); System.out.println (Thread.currentThread (). GetName ()+"rufen Sie Mythead.start ()"); mythead.start (); }}Ausgabe:
Hauptaufruf mythead.run () Hauptstufe RunningMain Call Mythead.Start () MyThread läuft
synchronisiert
In Java verfügt jedes Objekt über eine Synchronisationsschloss. Wenn wir die synchronisierte Methode des Objekts aufrufen, wird die Objektschloss erfasst und synchronisiert (OBJ) die Synchronisationsschloss des "OBJ -Objekts". Verschiedene Threads Zugriff auf die Synchronisationsschloss schließen sich gegenseitig aus. Die Synchronisationsschloss des Objekts kann nur zu einem bestimmten Zeitpunkt von einem Thread erfasst werden. Durch das Synchronisationsschloss können wir in mehreren Threads einen sich gegenseitig ausschließenden Zugriff auf das "Objekt/die Methode" erreichen. Zum Beispiel gibt es jetzt zwei Threads A und Thread B, die alle auf das "Synchronisierte Lock of Object OBJ" zugreifen. Nehmen wir an, dass Faden A irgendwann die "Obj -Synchronisationsschloss" erwerben und einige Operationen durchführen. Zu diesem Zeitpunkt versucht Thread B auch, das "Obj's Synchronization Lock" zu erwerben - Thread B wird nicht erwerben, es muss warten, bis Thread A die "Obj's Synchronisation Lock" veröffentlicht und nur ausgeführt werden kann.
Grundregeln
Artikel 1: Wenn ein Thread auf die "synchronisierte Methode" oder "synchronisierten Codeblock" von "einem bestimmten Objekt" zugreift, werden andere Threads vom Zugriff auf die "synchronisierte Methode" oder "Synchronisierter Codeblock" des "Objekts" blockiert.
Artikel 2: Wenn ein Thread auf die "synchronisierte Methode" oder "synchronisierten Codeblock" von "einem bestimmten Objekt" zugreift, können andere Threads weiterhin auf den asynchronisierten Codeblock von "dieses Objekt" zugreifen.
Artikel 3: Wenn ein Thread auf die "synchronisierte Methode" oder "synchronisierten Codeblock" von "einem bestimmten Objekt" zugreift, werden andere Threads aus dem Zugriff auf andere "synchronisierte Methoden" oder "Synchronisierter Codeblock" von "The Object" blockiert.
Synchronisierte Methode
public synchronisierte void foo1 () {System.out.println ("Synchronisierte Methode");} synchronisierter Codeblock public void foo2 () {synchronisiert (this) {System.out.println ("Synchronisierte Methode"); }}Dies im synchronisierten Codeblock bezieht sich auf das aktuelle Objekt. Dies kann auch durch andere Objekte ersetzt werden, die beispielsweise durch OBJ ersetzt werden, und foo2 () erwirbt die Synchronisationsschloss von OBJ, wenn sie synchronisiert ist (OBJ).
Synchronisierte Codeblöcke können konfliktbeschränkte Zugangsbereiche genauer steuern und manchmal effizienter abschneiden
Instanzschloss und Global Lock
Instanzverriegelung auf einem Instanzobjekt. Wenn die Klasse ein Singleton ist, hat das Schloss auch das Konzept eines globalen Schlosses. Das synchronisierte Schlüsselwort entspricht der Instanzschloss.
Global Lock- Dieses Schloss richtet sich an eine Klasse. Unabhängig davon, wie viele Objekte die Instanz sind, teilen die Threads das Schloss. Das globale Schloss entspricht statischer synchronisiertem (oder auf dem Objekt der Klasse oder des Klassenloaders dieser Klasse).
Pulbic Class Etwas {public synchronisierte void isynca () {} public synchronisierte void isyncb () {} public static synchronisierte void csynca () {} öffentliche statische statische synchronisierte void void csyncb () {}}}
(01) X.ISSYNCA () und X.ISSYNCB () können nicht gleichzeitig zugegriffen werden. Weil Issynca () und isSyncb () beide Synchronisationssperrungen sind, die auf dasselbe Objekt zugreifen (Objekt X)!
(02) X.ISSYNCA () und Y.ISSYNCA () können gleichzeitig zugegriffen werden. Da es nicht auf die Synchronisationsschloss desselben Objekts zugreift, greift X.ISSynca () auf die Synchronisationsschloss von X zu, während y.issynca () auf die Synchronisationsschloss von Y zugreift.
(03) x.csynca () und y.csyncb () können nicht gleichzeitig zugegriffen werden. Da CSYNCA () und CSYNCB () beide statische Typen sind, entspricht X.csynca () etwas. ISSynca () und Y.Csyncb () entspricht etwas. ISSyncb () haben eine Synchronisationsschloss und können nicht zur gleichen Zeit gefragt werden.
(04) X.ISSynca () und etwas.csynca () kann gleichzeitig zugegriffen werden. Da isynca () eine Instanzmethode ist, verwendet X.ISSYNCA () die Sperre von Objekt x; Während CSynca () eine statische Methode ist, kann CSYNCA () verstehen, dass es sich um ein "Klassenschloss" handelt. Daher können sie gleichzeitig zugegriffen werden.
Fadenblockierung und Weckwachen warten, benachrichtigen, benachrichtigen
In Object.java werden Schnittstellen wie Wait (), benachrichtigen () und Notifyall () definiert. Die Funktion von Wait () besteht darin, den aktuellen Thread in einen Wartezustand einzugeben, und Wait () lässt den aktuellen Thread auch das von ihm gehaltene Sperre loslassen. Die Rolle von Notify () und NotifyAll () besteht darin, den wartenden Thread auf dem aktuellen Objekt aufzuwecken. Notify () soll einen einzelnen Thread aufwachen, während Notifyall () alle Threads aufwecken soll.
Die API -Details zum Warten/Wachen in der Objektklasse sind wie folgt:
Benachrichtigen () - Wachen Sie einen einzelnen Thread auf, der auf diesen Objektmonitor wartet.
NotifyAll () - Weck alle Threads auf, die auf diesen Objektmonitor wartet.
Wait () - Stecken Sie den aktuellen Thread in eine "Warten- (Blockierungs-) Status" und "bis andere Threads die Methode benachrichtigen () oder notifyall () dieses Objekts aufrufen", und der aktuelle Thread wird erweckt (eingegeben in den "Ready State").
Warten Sie (langfristig) - Stecken Sie den aktuellen Thread in eine "Warten- (Blockierungs-) Status" und "Bis andere Threads die Methode des Objekts benachrichtigen () oder notifyall () () oder überschreiten Sie die angegebene Zeitspanne", und der aktuelle Thread wird erweckt (eingegeben in den "Bereitschaftszustand").
Warten Sie (langfristig, int nanos) - Lassen Sie den aktuellen Thread in einer "Warten- (Blockierungs-) Status" sein, bis ein anderer Thread die Methode des Objekts benachrichtigt () oder notifyAll () oder ein anderer Thread unterbricht den aktuellen Thread oder hat eine bestimmte Menge an Zeit überschritten, und der aktuelle Thread wird erweckt (in den "Ready State" eingegeben).
// WaitTest.javas Quellcodeklasse -Threada erweitert Thread {public threada (String name) {super (name); } public void run () {synchronized (this) {System.out.println (Thread.currentThread (). getName ()+"Anruf notify ()"); // Weck den aktuellen Wait -Thread benachrichtigen (); }}} public class waitTest {public static void main (String [] args) {threada t1 = new threada ("t1"); synchronisiert (t1) {try {// start "Thread t1" system.out.println (Thread.currentThread (). getName ()+"start t1"); t1.start (); // Der Haupt -Thread wartet darauf, dass T1 aufwacht. System.out.println (Thread.currentThread (). GetName ()+"wait ()"); t1.wait (); System.out.println (Thread.currentThread (). GetName ()+"Fortsetzung"); } catch (interruptedException e) {e.printstacktrace (); }}}}Ausgabe
Hauptstart T1Main Wait () T1 CALL NOTIFIFY () Main Fortsetzung
(01) Beachten Sie, dass der "Hauptfaden" in der Abbildung "Hauptfaden Haupt" darstellt. "Thread T1" repräsentiert "Thread T1" in Wartest. Und "Lock" repräsentiert "Synchronen des Objekts T1".
(02) "Haupt Thread" erstellt einen neuen "Thread T1" über New Threada ("T1"). Dann wird die "synchrone Schloss des T1 -Objekts" durch synchronisiert (T1) erhalten. Rufen Sie dann t1.start () an, um "Thread T1" zu starten.
(03) "Haupt Thread" führt t1.wait () aus, um "Lock of T1 -Objekt" zu veröffentlichen und in "Warte (Blocking) Status" zu gelangen. Warten Sie, bis Threads zu T1 -Objekten über Notify () oder NotifyAll () aufweckt werden.
(04) Nachdem "Thread T1" ausgeführt wurde, wird die "Sperre des aktuellen Objekts" durch synchronisiert (this) erhalten; Rufen Sie dann Notify () auf, um den "Wartefaden auf dem aktuellen Objekt" aufzuwecken, dh den "Haupt -Thread" aufzuwecken.
(05) Veröffentlichen Sie nach Abschluss "Thread T1" die "Sperre des aktuellen Objekts". Unmittelbar danach erwirbt der "Hauptfaden" das "Schloss des T1 -Objekts" und wird dann ausgeführt.
t1.wait () ist die Wait () -Methode, die durch "Thread T1" bezeichnet wird, aber der Ort, an dem T1.wait () aufgerufen wird, befindet sich in der "Haupt -Thread -Main". Der Haupt -Thread muss der "aktuelle Thread" sein, dh der laufende Status, bevor t1.wait () ausgeführt werden kann. Daher ist der "aktuelle Thread" zu diesem Zeitpunkt die "Haupt -Thread -Main"! Daher ist T1.wait (), den "Haupt -Thread" zu warten, nicht "Thread T1"!
Paket Thread.test; public class meldallTest {private static Object obj = new Object (); public static void main (String [] args) {threada t1 = new threada ("t1"); Threada t2 = new threada ("t2"); Threada t3 = new threada ("t3"); t1.start (); t2.Start (); t3.Start (); try {system.out.println (Thread.currentThread (). getName ()+"schlaf (3000)"); Thread.sleep (3000); } catch (interruptedException e) {e.printstacktrace (); } synchronized (obj) {system.out.println (Thread.currentThread (). getName ()+"notifyAll ()"); obj.notifyAll (); // wach t1.t2.t3 hier}} statische Klasse Threada erweitert Thread {public threada (String name) {super (name); } public void run () {synchronized (obj) {try {// printout result System.out.println (Thread.currentThread (). getName () + "Wait"); // Die OBJ -Objekt -Sperre obj.wawait () freigeben; // Ausdruckergebnis system.out.println (Thread.currentThread (). GetName () + "Fortsetzung"); } catch (interruptedException e) {e.printstacktrace (); }}}}}} Ausgabe:
T1 Waitmain Sleep (3000) T3 Waitt2 Waitmain Notifyall () T2 Fortsetzung 3 Fortsetzung
(01) 3 Threads "T1", "T2" und "T3" wurden erstellt und im Hauptfaden begonnen.
(02) Der Hauptfaden schläft 3 Sekunden im Schlaf (3000). Während des Hauptfadenschlafes für 3 Sekunden gehen wir davon aus, dass die drei Fäden "T1", "T2" und "T3" alle laufen. Nehmen Sie als Beispiel "T1". Wenn es ausgeführt wird, wird OBJ.wait () ausgeführt, um darauf zu warten, dass andere Themen durch notify () oder nofityAll () aufwecken. Aus dem gleichen Grund warten "T2" und "T3" auch darauf, dass andere Themen sie durch nofity () oder nofityAll () aufwecken.
(03) Der Hauptfaden schläft 3 Sekunden lang und läuft dann. Führen Sie obj.notifyall () aus, um den wartenden Thread auf OBJ aufzuwecken, dh die drei Threads "T1", "T2" und "T3" aufzuwecken. Unmittelbar nach dem Ausführen des Hauptfadens synchronisiert (OBJ) setzt der Hauptfaden das "OBJ Lock" frei. Auf diese Weise können "T1", "T2" und "T3" das "OBJ Lock" erhalten und weiter laufen!
Benachrichtigen, benachrichtigen und die Beziehung sperren
Funktionen wie Wait (), benachrichtigen () im Objekt wie synchronisiert werden die "Objektsynchronisationsschloss" betrieben.
Wait () lässt den "aktuellen Thread" warten. Da der Thread in den Wartezustand eingeht, sollte der Thread das "Synchronen Schloss" von seiner Schloss freigeben, andernfalls können andere Fäden das "Synchronenschloss" nicht erhalten und nicht in der Lage sein, auszuführen!
OK, nachdem der Thread -Anrufe warten (), wird das "Synchronen Schloss" von seinem Schloss veröffentlicht. Und gemäß der vorherigen Einführung wissen wir, dass der wartende Thread von notify () oder notifyAll () geweckt werden kann. Denken Sie nun bitte über eine Frage nach: Was wird auf der Grundlage des erwarteten Threads benachrichtigt ()? Oder wie hoch ist die Korrelation zwischen Wait () und Notify ()? Die Antwort lautet: Basierend auf "Objektsynchronisationsschloss".
Der Thread, der für das Aufwachen des wartenden Threads verantwortlich ist (wir nennen es "Wake up Thread"), kann den wartenden Thread erst nach dem Erhalten der "Synchronensperrung dieses Objekts" (die Synchronisationsschloss hier die Synchronisationsschloss des wartenden Threads) und das Aufrufen der Notify () oder Notifyall () -Methoden aufwachen. Obwohl der wartende Faden erweckt wird; Es kann jedoch nicht sofort ausgeführt werden, da der Wak-up-Thread "Synchronous Sperle für das Objekt" enthält. Sie müssen warten, bis der Wakup-Thread das "Synchronisationsschloss des Objekts" freigibt, bevor Sie das "Synchronisationsschloss des Objekts" erhalten und weiter ausgeführt werden können.
Kurz gesagt, benachrichtigen (), Wait () stützt sich auf "Synchronen Schloss", das von Objektschlössern gehalten wird, und jedes Objekt hat und nur eines! Aus diesem Grund werden Funktionen wie Notify (), Wait () in der Objektklasse definiert, nicht in der Thread -Klasse.
Gewindekonzessionen ergeben
Thread -Zugeständnisse verändern den Thread vom Ausführungszustand in den Bereitschaftszustand, so dass andere wartende Threads mit derselben Priorität die Ausführungsrechte erhalten können. Es ist jedoch nicht garantiert, dass andere Threads mit der gleichen Priorität definitiv Ausführungsrechte erhalten, nachdem die aktuellen Thread -Aufrufe () () () die gleichen Priorität erhalten. Es ist auch möglich, dass der aktuelle Thread in den "Laufstatus" eingeht und weiterhin ausgeführt wird.
Nachgeben und Warten
(01) Wait () soll den Thread den "laufenden Zustand" eingeben lassen, während nicht Rendite () den Thread den "Ready State" aus dem "Laufstatus" eingeben lässt.
(02) Wait () ist ein Synchronisationsschloss, das das von ihm gehaltene Objekt freisetzt, während die Methode reliefs () die Sperre nicht freigibt.
(03) Warten ist die Methode des Objekts, Ausbeute ist die Methode des Threads
Fadenschlaf
Die Funktion von Sleep () besteht darin, den aktuellen Fadenschlafen zu lassen, dh der aktuelle Thread wird vom "Laufstatus" zum "Schlaf (Blockierung)" eingebracht. Sleep () gibt die Schlafzeit an, und die Schlafzeit der Fäden ist größer als/gleich der Schlafzeit. Wenn der Thread erneut geweckt wird, wechselt er von einem "Blockierstatus" in einen "readigen Zustand" und wartet darauf, dass die CPU ausgeführt wird.
Der Unterschied zwischen Schlaf und Warten
Die Funktion von Wait () besteht darin, den aktuellen Thread den "Waiting (Blocking) aus dem" Laufstatus "einzugeben und auch die Synchronisationsschloss freizulassen. Die Funktion von Sleep () besteht darin, den aktuellen Thread in den" Schlaf (Blocking) aus dem "Laufstatus" einzugeben. (Das ist eigentlich nicht viel anders)
Wait () löst die Synchronisationsschloss des Objekts frei, während der Schlaf () das Schloss nicht freigibt
Warten ist die Methode des Objekts, Schlaf ist die Methode des Fadens
Verbinden
Lassen Sie den Hauptfaden warten, und der untergeordnete Thread kann weiter verlaufen, nachdem der Hauptfaden abgeschlossen ist.
unterbrechen
Wird verwendet, um einen blockierten Faden zu beenden
@Overridepublic void run () {try {while (true) {// Die Aufgabe ausführen ...}} catch (interruptedException ie) {// Aufgrund einer InterruptedException -Ausnahme, beenden Sie die while (true) Schleife und die Thread -Kündigungen! }}In der Zeit (wahr) erzeugt der Aufruf zu Interrupt () des Threads einen Interrupt -Anception -Interrupt. Die unterbrochene Erfassung ist draußen, während (wahr) draußen ist und damit die while (wahre) Schleife verlässt
Beendet einen Thread im Laufstatus
@Overridepublic void run () {while (! IsInterrupted ()) {// Task ausführen ...}}Gemeinsame Art, Fäden zu beenden
@OverridePublic void run () {try {// 1. isinterrupted () garantiert, dass der Thread beendet wird, solange der Interrupt true markiert ist. while (! is interrupted ()) {// Task ausführen ...}} catch (InterruptedException dh) {// 2. InterruptedException -Ausnahme garantiert, dass der Thread beendet wird, wenn eine InterruptedException -Ausnahme auftritt. }}
Priorität der Faden
Der Thread -Prioritätsbereich in Java beträgt 1 bis 10, und die Standardpriorität beträgt 5. Es gibt zwei Arten von Threads in Java: Benutzer -Thread und Daemon -Thread. Sie können durch die Isdaemon () -Methode unterschieden werden: Wenn Falsch zurückgegeben wird, bedeutet dies, dass der Thread ein "Benutzer -Thread" ist. Ansonsten ist es ein "Daemon -Thread". Benutzer-Threads führen im Allgemeinen Aufgaben auf Benutzerebene aus, während Daemon-Threads auch "Backend-Threads" sind, die im Allgemeinen zur Ausführung von Hintergrundaufgaben verwendet werden. Es ist zu beachten, dass der Java Virtual Machine beendet wird, nachdem der "Benutzer -Thread" abgeschlossen ist.
Jeder Thread hat eine Priorität. "Threads mit hoher Priorität" werden der Ausführung gegenüber "Threads mit niedriger Priorität" vorausgehen. Jeder Faden kann als Daemon oder Nicht-Daemon gekennzeichnet werden. Beim Erstellen eines neuen untergeordneten Threads in einem laufenden Haupt -Thread wird die Priorität des Kinderthreads auf die gleiche "Priorität des Haupt -Threads, die es erstellt" festgelegt, und "Das untergeordnete Thread ist der Daemon -Thread", wenn "der Haupt -Thread, der es erstellt hat, ein Daemon -Thread ist".
Wenn eine java-virtuelle Maschine gestartet wird, gibt es normalerweise einen einzelnen Nicht-Dahemon-Thread (dieser Thread wird über die main () -Methode gestartet). Der JVM läuft bis eine der folgenden Bedingungen auftritt und der JVM den Lauf beendet:
(01) Die METHODE EXIT () wird aufgerufen und exit () hat die Erlaubnis, normal ausgeführt zu werden.
(02) Alle "Nicht-Daemon-Threads" sind tot (dh nur "Daemon-Threads" im JVM).
Dämon
(01) Der Haupt -Thread -Haupthaupt ist der Benutzer -Thread, und der untergeordnete Thread T1 ist auch der Benutzer -Thread.
(02) T2 ist der Daemon -Thread. Wenn die "Haupt-Thread-Haupt-" und "Sub-Thread T1" (sie sind beide Benutzer-Threads) ausgeführt und nur der Daemon-Thread T2 übrig ist, beendet das JVM automatisch.
Erzeuger- und Verbraucherprobleme
(01) Der Produzent produziert nur, wenn das Lagerhaus nicht voll ist, und stoppt die Produktion, wenn das Lagerhaus voll ist.
(02) Verbraucher können nur dann konsumieren, wenn sie Produkte im Lager haben, und warten, wenn sie leere Lager haben.
(03) Wenn die Verbraucher feststellen, dass es im Lager kein Produkt gibt, das kein Produkt zu konsumieren ist, werden sie den Hersteller benachrichtigen.
(04) Wenn die Hersteller konsumierbare Produkte produzieren, sollten sie die wartenden Verbraucher zum Konsumieren benachrichtigen.
Kommunikation zwischen Themen
Methode: Shared Memory und Messaging
Shared Memory: Thread A und Thread B Share Memory, Thread A aktualisiert den Wert der gemeinsam genutzten Variablen, aktualisiert ihn in den Hauptspeicher, und Thread B geht zum Hauptspeicher, um die aktualisierten Variablen von Thread A zu lesen. Der gesamte Kommunikationsprozess muss durch den Hauptspeicher geleitet werden. Die Synchronisation wird explizit durchgeführt.
Wenn eine Variable volatil vom Typ ist, ist das Lesen und Schreiben der Variablen atomar. Wenn es sich um mehrere volatile Operationen oder zusammengesetzte Operationen handelt, ähnlich wie volatil ++, sind diese Operationen nicht in ihrer Gesamtheit atomar.
Die volatile Variable selbst hat die folgenden Eigenschaften:
[Sichtbarkeit]: Beim Lesen einer volatilen Variablen können Sie immer das letzte Schreiben in die flüchtige Variable (jeden Thread) sehen.
[Atomizität]: Es hat Atomizität für das Lese-/Schreiben einer einzelnen volatilen Variablen, hat jedoch keine Atomizität für zusammengesetzte Operationen, ähnlich wie volatil ++.
VOLATILE WRITE: Beim Schreiben einer volatilen Variablen spülen JMM die gemeinsame Variable im lokalen Speicher, der dem Thread zum Hauptspeicher entspricht.
Völliger Lesen: Beim Lesen einer volatilen Variablen wird JMM den lokalen Speicher ungültig, der dem Thread entspricht. Der Thread liest als nächstes die gemeinsame Variable aus dem Hauptspeicher.
Nachrichtenzustellung: Das Senden einer Nachricht wird implizit durchgeführt, bevor die Nachricht akzeptiert wird.
ThreadLocal
ThreadLocal wird nicht verwendet, um das Problem des Multi-Thread-Zugriffs auf freigegebene Objekte zu lösen. Im Allgemeinen ist das Objekt zum ThreadLocal.set () ein Objekt, das vom Thread selbst verwendet wird. Auf andere Themen müssen nicht zugegriffen werden und können nicht zugegriffen werden. ThreadLocal ermöglicht es jedem Thread, sein eigenes unabhängiges Objekt beizubehalten. Es wird nicht über threadLocal.set () implementiert, sondern ein Objekt, das durch die Funktionsweise des neuen Objekts in jedem Thread erstellt wurde. Jeder Thread erstellt eine, keine Kopie oder Kopie des Objekts. Der Verweis auf das neu erstellte Objekt wird über ThreadLocal.set () auf die eigene Karte jedes Threads gespeichert. Jeder Thread hat eine solche Karte. Wenn ThreadLocal.get () ausgeführt wird, nimmt jeder Thread das von seiner eigene Karte eingegebene Objekt heraus. Daher wird das Objekt in jedem Thread herausgenommen. Die ThreadLocal -Instanz wird als Kartenschlüssel verwendet. Wenn das, was ThreadLocal.set () eingibt, das gleiche Objekt ist, das von mehreren Threads gemeinsam genutzt wird, erhält der ThreadLocal.get () mehrerer Threads das gemeinsame Objekt selbst und es gibt immer noch ein gleichzeitiges Zugriffsproblem.
Eine Implementierung von ThreadLocal
Import Java.util.Collections; import Java.util.hashMap; import Java.util.map; /** * Klasse mit ThreadLocal * * @Author Leizhimin 2010-1-5 10:35:27 */Public Class Mythreadlocal {// Definieren Sie eine Threadlokal-Variable zum Speichern von int oder Integer data Private Com.lavasoft.Test2.ThreadLocal <Integer> TL = New Com.lavasoft.Test2. initialValue () {return 0; }}; public Integer getNextnum () {// den Wert von TL und add 1 ab und aktualisiert den Wert von t1 tl.set (tl.get () + 1); return tl.get (); }} Klasse ThreadLocal <T> {private map <thread, t> map = collections.synchronizedMap (neuer Hashmap <Thread, t> ()); public threadLocal () {} protected t initialValue () {return null; } public t get () {thread t = thread.currentThread (); T obj = map.get (t); if (obj == null &&! map.containsKey (t)) {obj = initialValue (); map.put (t, obj); } return obj; } public void set (t value) {map.put (thread.currentThread (), value); } public void remove () {map.remove (thread.currentThread ()); }}Tatsächlich macht ThreadLocal dies:
public t get () {Thread t = thread.currentThread (); ThreadLocalMap map = getMap (t); if (map! if (e! = null) return (t) E. value; } return setInitialValue (); }