Java multithreading (einer)
Als sehr wichtiger Wissenspunkt in Java ist es immer noch notwendig, es hier zusammenzufassen.
1. Der Lebenszyklus eines Fadens und der fünf Grundzustände
In Bezug auf den Lebenszyklus von Fäden in Java schauen wir uns zunächst das folgende klassische Bild an:
Die obige Abbildung deckt im Grunde die wichtigen Wissenspunkte des Multi-Threading in Java ab. Sobald Sie die Wissenspunkte in der obigen Abbildung beherrschen, beherrschen Sie das Multi-Threading in Java im Grunde genommen. Hauptsächlich einschließlich:
Java -Threads haben fünf Grundzustände
Neuer Zustand (neu): Wenn ein Thread -Objektpaar erstellt wird, tritt ein neuer Zustand ein, wie z. B. Thread t = new myThread ();
Ready State (Runnable): Wenn die Start () -Methode des Thread -Objekts (t.Start ();), tritt der Thread in den Bereitschaftszustand ein. Ein Thread im rede Zustand bedeutet nur, dass der Thread fertig ist und darauf wartet, dass die CPU die Ausführung jederzeit plant, und nicht, dass der Thread unmittelbar nach T.Start () ausgeführt wird.
Auslaufstatus: Wenn die CPU beginnt, Threads im vorbereitenden Zustand zu planen, kann der Thread wirklich ausgeführt werden, dh in den laufenden Status. Hinweis: Der Ready -Status ist der einzige Eintrag in den laufenden Status, dh wenn ein Thread in den ausführenden Zustand eingeben möchte, muss er zunächst im vorbereitenden Zustand sein.
Blockierter Zustand: Aus irgendeinem Grund gibt ein Thread im laufenden Status die Verwendung der CPU vorübergehend auf und stoppt die Ausführung. Zu diesem Zeitpunkt tritt es in den Blockierstaat ein. Es wird nicht die Chance haben, von der CPU erneut aufgerufen zu werden, um in den laufenden Zustand einzugeben. Nach den Gründen des Blockierens können Blockierungszustände in drei Typen unterteilt werden:
1. Warten auf die Blockierung: Der Thread im laufenden Status führt die Wait () -Methode aus, damit der Thread das Warten auf den Blockierstatus eingeht.
2. Synchronisiertes Blockieren- Der Thread erfasst das synchronisierte Synchronisationsschloss (da das Schloss von anderen Fäden besetzt ist) nicht in den synchronisierten Blockierungszustand eingetragen.
3. Andere Blockierung-Der Thread tritt in einen Blockierungsstatus ein, indem er Schlaf () oder Join () des Threads anruft oder eine E/A-Anfrage ausstellt. 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.
TOT: Der Thread hat die Ausführung der Ausnahme ausgesetzt oder verlässt die Run () -Methode aufgrund einer Ausnahme, und der Thread beendet seinen Lebenszyklus.
2. Schöpfung und Start von Java Multithreads
In Java gibt es drei grundlegende Formen der Thread -Erstellung
1. Erben Sie die Thread -Klasse und überschreiben Sie die Run () -Methode der Klasse.
Klasse myThread erweitert Thread {private int i = 0; @Override public void run () {für (i = 0; i <100; i ++) {System.out.println (Thread.CurrentThread (). GetName () + "" + i); }}} public class threadTest {public static void main (String [] args) {für (int i = 0; i <100; i ++) {System.out.println (Thread.currentThread (). getName () + " + i); if (i == 30) {Thread myThread1 = new myThread (); // Erstellen Sie einen neuen Thread mythread1 Dieser Thread tritt in den neuen Status -Thread mythread2 = new MyThread () ein; // Erstellen Sie einen neuen Thread myThread2 Dieser Thread tritt in den neuen Status mythread1.start () ein; // Rufen Sie die Methode start () an, damit der Thread den Ready State MyThead2.Start () eingibt. // Rufen Sie die Methode start () auf, um den Thread den Ready -Status einzugeben}}}}Wie oben gezeigt, wird ein neues MyThread der Thread -Klasse definiert, indem die Run () -Methode überschrieben wird, wobei die Methode des Methode der Run () -Methode die Aufgabe darstellt, die der Thread ausführen muss, und als Thread -Ausführungsgremium bezeichnet wird. Beim Erstellen dieses Thread -Klassenobjekts wird ein neuer Thread erstellt und tritt in den neuen Thread -Status ein. Wenn Sie die vom Thread -Objekt verwiesene Start () -Methode aufrufen, tritt der Thread in den Bereitschaftszustand ein. Zu diesem Zeitpunkt kann der Thread je nach Timing der CPU nicht sofort ausgeführt werden.
2. Implementieren Sie die Runnable -Schnittstelle und überschreiben Sie die Run () -Methode der Schnittstelle. Die Run () -Methode ist auch ein Thread -Ausführungsgremium, erstellen Sie eine Instanz der Runnable -Implementierungsklasse und verwenden diese Instanz als Ziel der Thread -Klasse, um ein Thread -Objekt zu erstellen. Das Thread -Objekt ist das reale Thread -Objekt.
Klasse myrunnable implements runnable {private int i = 0; @Override public void run () {für (i = 0; i <100; i ++) {System.out.println (Thread.CurrentThread (). GetName () + "" + i); }}} public class threadTest {public static void main (String [] args) {für (int i = 0; i <100; i ++) {System.out.println (Thread.currentThread (). getName () + " + i); if (i == 30) {runnable myrunnable = new Myrunnable (); // Erstellen Sie ein Objekt von Runnable -Implementierungsklassen Thread1 = neuer Thread (Myrunnable); // Erstellen Sie einen neuen Thread mit Myrunnable als Thread -Ziel -Thread -Thread2 = neuer Thread (Myrunnable); Thread1.Start (); // rufen Sie die Methode start () auf, um den Thread den thread2 -status -Thread2.Start () einzugeben. }}}} Ich glaube, dass jeder mit den oben genannten zwei Möglichkeiten vertraut ist, neue Threads zu erstellen. Wie ist die Beziehung zwischen Thread und Runnable? Schauen wir uns zunächst das folgende Beispiel an.
public class threadTest {public static void main (String [] args) {für (int i = 0; i <100; i ++) {System.out.println (Thread.currentThread (). getName () + " + i); if (i == 30) {runnable myrunnable = new Myrunnable (); Thread Thread = New MyThread (Myrunnable); Thread.Start (); }}}} Klasse Myrunnable Geräte runnable {private int i = 0; @Override public void run () {System.out.println ("in Myrunnable Run"); für (i = 0; i <100; i ++) {System.out.println (thread.currentThread (). getName () + "" + i); }}} Klasse myThread erweitert Thread {private int i = 0; public myThread (runnable runnable) {super (runnable); } @Override public void run () {System.out.println ("in MyThread Run"); für (i = 0; i <100; i ++) {System.out.println (thread.currentThread (). getName () + "" + i); }}}In ähnlicher Weise gilt dies auch für das Erstellen von Threads, die die Runnable -Schnittstelle implementieren. Der Unterschied besteht darin
1 Thread = neuer MyThread (Myrunnable);
Kann diese Methode also erfolgreich einen neuen Thread erstellen? Die Antwort lautet ja. Was den Thread -Ausführungskörper zu diesem Zeitpunkt betrifft, so ist die Run () -Methode in der Myrunnable -Schnittstelle oder in der Run () -Methode in der MyThread -Klasse? Durch die Ausgabe wissen wir, dass der Thread -Ausführungskörper die Run () -Methode in der MyThread -Klasse ist. Tatsächlich ist der Grund sehr einfach, da die Thread -Klasse selbst auch die Runnable -Schnittstelle implementiert und die Run () -Methode zuerst in der Runnable -Schnittstelle definiert ist.
public interface runnable {public abstract void run (); } Schauen wir uns die Implementierung der Run () -Methode in der Runnable -Schnittstelle in der Thread -Klasse an:
@Override public void run () {if (target! = Null) {target.run (); }}Das heißt, bei der Ausführung der Run () -Methode in der Thread -Klasse wird zunächst festgestellt, ob das Ziel existiert. Wenn es vorhanden ist, wird die Run () -Methode im Ziel ausgeführt, dh die Run () -Methode in der Klasse, die die Runnable -Schnittstelle implementiert und die Run () -Methode überschreibt. In den oben angegebenen Spalten wird jedoch aufgrund der Existenz des Polymorphismus die Run () -Methode in der Thread -Klasse überhaupt nicht ausgeführt, sondern der Laufzeittyp, dh die Run () -Methode in der MyThread -Klasse, wird direkt ausgeführt.
3. Erstellen Sie Threads mit Callable und zukünftigen Schnittstellen. Insbesondere erstellt es eine Implementierungsklasse für die Callable -Schnittstelle und implementiert die Clall () -Methode. Verwenden Sie die Futuretask -Klasse, um das Objekt für Callable -Implementierungsklassen einzuwickeln und dieses Futuretask -Objekt als Ziel des Thread -Objekts, um einen Thread zu erstellen.
Es scheint ein bisschen kompliziert, aber es wird klar sein, wenn Sie sich ein Beispiel direkt ansehen.
public class threadTest {public static void main (String [] args) {Callable <Integer> mycallable = new MyCallable (); // MyCallable -Objekt -Futuretask <Ganzzahl> ft = New Futuretask <Ganzzahl> (myCallable); // Futuretask verwenden, um das mycallable Objekt für (int i = 0; i <100; i ++) {System.out.println (Thread.currentThread (). GetName () + "" + i) zu wickeln; if (i == 30) {Thread thread = neuer Thread (ft); // Futuretask -Objekt erstellt einen neuen Thread als Ziel des Thread -Objekt -Threads.start (); // Der Thread gibt in den Ready State}} System.out.println ("Der Haupt -Thread für Schleife wurde ausgeführt."); try {int sum = ft.get (); // das Ergebnis erhalten, das von der CALL () -Methode im neu erstellten neuen Thread System.out.println ("sum =" + sum) zurückgegeben wird; } catch (interruptedException e) {e.printstacktrace (); } catch (executionException e) {e.printstacktrace (); }}} Klasse mycallable implementiert Callable <GanzEger> {private int i = 0; // Im Gegensatz zur Methode run () hat die CALL () -Methode einen Rückgabewert @Override public Integer call () {int sum = 0; für (; i <100; i ++) {System.out.println (Thread.currentThread (). getName () + "" + i); sum += i; } Return Sum; }}Zunächst stellten wir fest, dass bei der Implementierung der Callable -Schnittstelle die Run () -Methode nicht mehr die Run () -Methode, sondern die Call () -Methode ist. Diese CALL () -Methode ist die Thread -Ausführungskörper und hat auch einen Rückgabewert! Beim Erstellen eines neuen Threads wird das mykallierbare Objekt durch Futuretask eingewickelt und dient auch als Ziel für das Thread -Objekt. Schauen Sie sich dann die Definition der Futuretask -Klasse an:
öffentliche Klasse Futuretask <V> Implementiert RunnableFuture <V> {// ....} public interface RunnableFuture <V> erweitert Runnable, Future <V> {void run (); }Daher stellten wir fest, dass die Futuretask -Klasse sowohl runnable als auch künftige Schnittstellen tatsächlich implementiert, was sie über die doppelten Eigenschaften der Zukunft und der Runnable verfügt. Durch die Runnable -Funktion kann es als Ziel des Thread -Objekts verwendet werden, und die zukünftige Funktion ermöglicht es ihm, den Rückgabewert der Call () -Methode im neu erstellten Thread zu erhalten.
Nachdem wir dieses Programm ausgeführt haben, stellen wir fest, dass Sum = 4950 immer die letzte Ausgabe ist. "Der Hauptfaden für die Schleife wurde ausgeführt ..." wird wahrscheinlich in der Mitte der Kinderfadenschleife ausgegeben. Aus dem Thread -Planungsmechanismus der CPU wissen wir, dass es kein Problem mit dem Ausgangszeitpunkt "Der Haupt -Thread für die Schleife wurde ausgeführt wurde ...". Warum wird Summe = 4950 für immer ausgegeben?
Der Grund dafür ist, dass wenn die Methode des untergeordneten Threads CALL () über die Methode ft.get () erhalten wird, wenn die Methode des untergeordneten Threads noch nicht ausgeführt wurde, blockiert die Methode ft.get (), bis die Methode call () ausgeführt wird, bevor der Rückgabewert erhalten werden kann.
Die obigen erklärt hauptsächlich drei gängige Methoden der Fadenerstellung. Für das Start von Threads werden sie alle als start () -Methode des Thread -Objekts bezeichnet. Es ist wichtig zu beachten, dass die Start () -Methode nicht zweimal auf demselben Thread -Objekt aufgerufen werden kann.
III. Bereit, Run- und Todstatus von Java Multithreading
Der Ready -Status wird in den laufenden Status umgewandelt: Wenn dieser Thread die Prozessorressource erhält;
Der laufende Status wird in den Ready -Status umgewandelt: Wenn dieser Thread die Rendite () -Methode aktiv aufruft oder die Prozessorressourcen während des Laufens verliert.
Der laufende Zustand wird in den toten Zustand umgewandelt: Wenn die Thread -Ausführungsbehörde abgeschlossen ist oder eine Ausnahme auftritt.
Es sollte hier angemerkt werden, dass, wenn die Rendite () -Methode des Threads aufgerufen wird, der Thread vom laufenden Zustand in den Bereitschaftszustand wechselt, aber welcher Thread im Bereitschaftszustand der CPU geplant ist, hat eine gewisse Zufälligkeit. Daher kann es geschehen, dass die CPU nach dem A -Thread die Rendite () -Methode aufruft, die CPU den A Thread noch plant.
Aufgrund der tatsächlichen geschäftlichen Anforderungen wird häufig aufgetaucht, dass ein Thread mit einer bestimmten Gelegenheit beendet werden muss, damit er in einen toten Zustand eintritt. Die derzeit häufigste Methode besteht darin, eine boolesche Variable festzulegen, und wenn die Bedingungen erfüllt sind, wird die Thread -Ausführungsbehörde schnell ausgeführt. wie:
public class threadtest {public static void main (String [] args) {Myrunnable Myrunnable = new Myrunnable (); Thread = neuer Thread (myrunnable); für (int i = 0; i <100; i ++) {System.out.println (thread.currentThread (). getName () + "" + i); if (i == 30) {thread.start (); } if (i == 40) {Myrunnable.StOpthead (); }}}} Klasse myrunnable implements runnable {private boolean stop; @Override public void run () {für (int i = 0; i <100 &&! Stop; i ++) {System.out.println (Thread.CurrentThread (). GetName () + "" i); }} public void stopThread () {this.stop = true; }}Wir werden verwandte Artikel in Zukunft weiterhin aussortieren. Vielen Dank für Ihre Unterstützung für diese Seite!
Artikelserie:
Erläuterung von Java-Multi-Thread-Instanzen (i)
Detaillierte Erklärung von Java-Multi-Thread-Instanzen (ii)
Detaillierte Erklärung von Java-Multi-Threade-Instanzen (III)