Thread ist die Grundeinheit des Betriebssystembetriebs. Er ist in einem Prozess gekapselt. Auch wenn wir keinen Thread manuell erstellen, wird im Prozess ein Standardthread ausgeführt.
Wenn wir für die JVM ein Single-Thread-Programm zur Ausführung schreiben, werden in der JVM mindestens zwei Threads ausgeführt, einer ist das von uns erstellte Programm und der andere ist die Speicherbereinigung.
Grundlegende Informationen zum Thread
Über die Methode Thread.currentThread() können wir einige Informationen über den aktuellen Thread erhalten und diese ändern.
Schauen wir uns den folgenden Code an:
Thread.currentThread().setName("Test");
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
name = Thread.currentThread().getName();
Priorität = Thread.currentThread().getPriority();
groupName = Thread.currentThread().getThreadGroup().getName();
isDaemon = Thread.currentThread().isDaemon();
System.out.println("Thread-Name:" + Name);
System.out.println("Priorität:" + Priorität);
GroupName : Jeder Thread befindet sich standardmäßig in einer Thread-Gruppe. Eine Thread-Gruppe kann auch Unter-Thread-Gruppen enthalten, sodass Threads und Thread-Gruppen eine Baumstruktur bilden.
Name : Jeder Thread hat einen Namen. Wenn er nicht explizit angegeben wird, lautet die Namensregel „Thread-xxx“.
Priorität : Jeder Thread hat seine eigene Priorität, und die Art und Weise, wie die JVM mit der Priorität umgeht, ist „präventiv“. Wenn die JVM einen Thread mit hoher Priorität findet, führt sie den Thread sofort aus. Bei mehreren Threads mit gleicher Priorität fragt die JVM diese ab. Die Thread-Priorität von Java reicht von 1 bis 10, wobei der Standardwert 5 ist. Die Thread-Klasse definiert zwei Konstanten: MIN_PRIORITY und MAX_PRIORITY, um die höchste und niedrigste Priorität darzustellen.
Wir können uns den folgenden Code ansehen, der zwei Threads mit unterschiedlichen Prioritäten definiert:
Thread thread2 = neuer Thread("high")
{
public void run()
{
for (int i = 0; i < 5; i++)
{
System.out.println("Thread 2 läuft.");
}
}
};
thread1.setPriority(Thread.MIN_PRIORITY);
thread2.setPriority(Thread.MAX_PRIORITY);
thread1.start();
thread2.start();
}
thread1.start();
}
So erstellen Sie einen Thread
Der obige Inhalt zeigt alle einige Informationen im Standardthread. Wie erstelle ich also einen Thread? In Java gibt es drei Möglichkeiten, Threads zu erstellen.
Threads in Java erben entweder die Thread-Klasse oder implementieren die Runnable-Schnittstelle. Lassen Sie uns sie einzeln durchgehen.
Verwenden Sie innere Klassen, um Threads zu erstellen
Wir können innere Klassen verwenden, um Threads zu erstellen. Der Prozess besteht darin, eine Variable vom Typ Thread zu deklarieren und die Ausführungsmethode zu überschreiben. Der Beispielcode lautet wie folgt:
Wir können eine Klasse von Thread ableiten und ihre Ausführungsmethode auf ähnliche Weise wie oben überschreiben. Der Beispielcode lautet wie folgt:
public static void createThreadBySubClass()
{
MyThread thread = new MyThread();
thread.start();
}
Wir können eine Klasse definieren, um die Runnable-Schnittstelle zu implementieren, und dann eine Instanz dieser Klasse als Parameter verwenden, um den Thread-Variablenkonstruktor zu erstellen. Der Beispielcode lautet wie folgt:
public static void createThreadByRunnable()
{
MyRunnable runnable = new MyRunnable();
Thread thread = neuer Thread (ausführbar);
thread.start();
}
Dies betrifft den Ausführungsmodus von Multithreading in Java. Wenn Multithreading in Java ausgeführt wird, gibt es Unterschiede zwischen „Multi-Objekt-Multi-Threading“ und „Einzelobjekt-Multi-Threading“:
Multi-Objekt-Multithreading : Das Programm erstellt während der Ausführung mehrere Thread-Objekte, und für jedes Objekt wird ein Thread ausgeführt.
Einzelobjekt-Multithreading : Das Programm erstellt während der Ausführung ein Thread-Objekt und führt darauf mehrere Threads aus.
Aus Sicht der Thread-Synchronisierung und -Planung ist Multi-Objekt-Multi-Threading offensichtlich einfacher. Von den oben genannten drei Thread-Erstellungsmethoden sind die ersten beiden „Multi-Objekt-Multi-Thread“ und die dritte kann entweder „Multi-Objekt-Multi-Thread“ oder „Einzel-Objekt-Single-Thread“ verwenden.
Schauen wir uns den folgenden Beispielcode an, der die Object.notify-Methode verwendet, um einen Thread für das Objekt zu aktivieren, und die Object.notifyAll-Methode aktiviert alle Threads für das Objekt.
public static void main(String[] args) löst eine InterruptedException aus
{
notifyTest();
notifyTest2();
notifyTest3();
}
private static void notifyTest() löst eine InterruptedException aus
{
MyThread[] arrThreads = new MyThread[3];
for (int i = 0; i < arrThreads.length; i++)
{
arrThreads[i] = new MyThread();
arrThreads[i].id = i;
arrThreads[i].setDaemon(true);
arrThreads[i].start();
}
Thread.sleep(500);
for (int i = 0; i < arrThreads.length; i++)
{
synchronisiert(arrThreads[i])
{
arrThreads[i].notify();
}
}
}
private static void notifyTest2() löst eine InterruptedException aus
{
MyRunner[] arrMyRunners = new MyRunner[3];
Thread[] arrThreads = neuer Thread[3];
for (int i = 0; i < arrThreads.length; i++)
{
arrMyRunners[i] = new MyRunner();
arrMyRunners[i].id = i;
arrThreads[i] = new Thread(arrMyRunners[i]);
arrThreads[i].setDaemon(true);
arrThreads[i].start();
}
Thread.sleep(500);
for (int i = 0; i < arrMyRunners.length; i++)
{
synchronisiert(arrMyRunners[i])
{
arrMyRunners[i].notify();
}
}
}
private static void notifyTest3() löst eine InterruptedException aus
{
MyRunner runner = new MyRunner();
Thread[] arrThreads = neuer Thread[3];
for (int i = 0; i < arrThreads.length; i++)
{
arrThreads[i] = new Thread(runner);
arrThreads[i].setDaemon(true);
arrThreads[i].start();
}
Thread.sleep(500);
synchronisiert (Läufer)
{
runner.notifyAll();
}
}
}
Die Klasse MyThread erweitert Thread
{
öffentliche int id = 0;
public void run()
{
System.out.println("Thread " + id + " ist für 5 Minuten in den Ruhezustand bereit.");
versuchen
{
synchronisiert(dies)
{
this.wait(5*60*1000);
}
}
Catch(InterruptedException ex)
{
ex.printStackTrace();
}
System.out.println("Der Thread „th“ + id + „wurde aktiviert.“);
}
}
Die Klasse MyRunner implementiert Runnable
{
öffentliche int id = 0;
public void run()
{
System.out.println("Thread " + id + " ist für 5 Minuten in den Ruhezustand bereit.");
versuchen
{
synchronisiert(dies)
{
this.wait(5*60*1000);
}
}
Catch(InterruptedException ex)
{
ex.printStackTrace();
}
System.out.println("Der Thread „th“ + id + „wurde aktiviert.“);
}
}
Die notifyAll-Methode eignet sich für das Szenario „Einzelobjekt mit mehreren Threads“, da die notify-Methode nur einen Thread für das Objekt zufällig aktiviert.
Thread-Statuswechsel
Für einen Thread kann der Status des Threads während dieses Prozesses vom Zeitpunkt seiner Erstellung bis zum Ende des Threads wie folgt aussehen:
Erstellung: Es gibt bereits eine Thread-Instanz, der CPU sind jedoch noch Ressourcen und Zeitscheiben zugewiesen.
Bereit: Der Thread hat alle zum Ausführen erforderlichen Ressourcen erhalten und wartet nur darauf, dass die CPU die Zeit einplant.
Läuft: Der Thread befindet sich in der aktuellen CPU-Zeitscheibe und führt die zugehörige Logik aus.
Ruhezustand: Im Allgemeinen der Zustand nach dem Aufruf von Thread.sleep. Zu diesem Zeitpunkt enthält der Thread noch verschiedene für den Betrieb erforderliche Ressourcen, wird jedoch nicht von der CPU geplant.
Suspend: Im Allgemeinen der Status nach dem Aufruf von Thread.suspend. Ähnlich wie beim Ruhezustand plant die CPU den Thread nicht. Der Unterschied besteht darin, dass der Thread in diesem Status alle Ressourcen freigibt.
Tod: Der Thread endet oder die Thread.stop-Methode wird aufgerufen.
Als nächstes zeigen wir, wie man den Thread-Status wechselt. Zuerst verwenden wir die folgende Methode:
Thread() oder Thread(Runnable): Konstruieren Sie einen Thread.
Thread.start: Einen Thread starten.
Thread.sleep: Schalten Sie den Thread in den Ruhezustand.
Thread.interrupt: Unterbrechen Sie die Ausführung des Threads.
Thread.join: Warten Sie, bis ein Thread endet.
Thread.yield: Dem Thread seine Ausführungszeit auf der CPU entziehen und auf die nächste Planung warten.
Object.wait: Sperrt alle Threads für das Objekt und wird erst nach der Benachrichtigungsmethode weiter ausgeführt.
Object.notify: Weckt nach dem Zufallsprinzip einen Thread für das Objekt auf.
Object.notifyAll: Weckt alle Threads auf Object auf.
Jetzt ist Demonstrationszeit! ! !
Thread warten und aufwachen
Hier werden hauptsächlich die Methoden Object.wait und Object.notify verwendet, siehe oben die Notify-Instanz. Es ist zu beachten, dass sowohl „wait“ als auch „notify“ auf dasselbe Objekt abzielen müssen. Wenn wir einen Thread durch Implementierung der Runnable-Schnittstelle erstellen, sollten wir diese beiden Methoden für das Runnable-Objekt anstelle des Thread-Objekts verwenden.
Thread Schlafen und Aufwachen
public static void main(String[] args) löst eine InterruptedException aus
{
sleepTest();
}
private static void sleepTest() löst eine InterruptedException aus
{
Thread-Thread = neuer Thread()
{
public void run()
{
System.out.println("Thread" + Thread.currentThread().getName() + "Es wird 5 Minuten lang schlafen.");
versuchen
{
Thread.sleep(5*60*1000);
}
Catch(InterruptedException ex)
{
System.out.println("Thread" + Thread.currentThread().getName() + "Ruhezustand wurde unterbrochen.");
}
System.out.println("Thread" + Thread.currentThread().getName() + "Ruhezustand beendet.");
}
};
thread.setDaemon(true);
thread.start();
Thread.sleep(500);
thread.interrupt();
}
}
Obwohl es eine Thread.stop-Methode gibt, wird diese Methode nicht empfohlen. Wir können den oben genannten Schlaf- und Weckmechanismus verwenden, um den Thread bei der Verarbeitung von IterruptedException beenden zu lassen.
public static void main(String[] args) löst eine InterruptedException aus
{
stopTest();
}
private static void stopTest() löst eine InterruptedException aus
{
Thread-Thread = neuer Thread()
{
public void run()
{
System.out.println("Der Thread wird ausgeführt.");
versuchen
{
Thread.sleep(1*60*1000);
}
Catch(InterruptedException ex)
{
System.out.println("Thread unterbrechen, Thread beenden");
zurückkehren;
}
System.out.println("Der Thread wurde normal beendet.");
}
};
thread.start();
Thread.sleep(500);
thread.interrupt();
}
}
Wenn wir 10 Unterthreads im Hauptthread erstellen und dann erwarten wir, dass der Hauptthread nach Abschluss aller 10 Unterthreads die nächste Logik ausführt. Zu diesem Zeitpunkt ist es Zeit für das Erscheinen von Thread.join.
public static void main(String[] args) löst eine InterruptedException aus
{
joinTest();
}
private static void joinTest() löst eine InterruptedException aus
{
Thread-Thread = neuer Thread()
{
public void run()
{
versuchen
{
for(int i = 0; i < 5; i++)
{
System.out.println("Der Thread wird ausgeführt.");
Thread.sleep(1000);
}
}
Catch(InterruptedException ex)
{
ex.printStackTrace();
}
}
};
thread.setDaemon(true);
thread.start();
Thread.sleep(1000);
thread.join();
System.out.println("Der Hauptthread wurde normal beendet.");
}
}
Wir wissen, dass sich alle Threads unter einem Prozess den Speicherplatz teilen. Wie übertragen wir also Nachrichten zwischen verschiedenen Threads? Bei der Überprüfung von Java I/O haben wir über PipedStream und PipedReader gesprochen, und hier kommen sie ins Spiel.
Die folgenden beiden Beispiele haben genau die gleichen Funktionen. Der Unterschied besteht darin, dass eines Stream und das andere Reader/Writer verwendet.
Thread thread1 = neuer Thread()
{
public void run()
{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
versuchen
{
while(true)
{
String message = br.readLine();
pos.write(message.getBytes());
if (message.equals("end")) break;
}
br.close();
pos.close();
}
Catch (Ausnahme ex)
{
ex.printStackTrace();
}
}
};
Thread thread2 = neuer Thread()
{
public void run()
{
byte[] buffer = neues byte[1024];
int bytesRead = 0;
versuchen
{
while((bytesRead = pis.read(buffer, 0, buffer.length)) != -1)
{
System.out.println(new String(buffer));
if (new String(buffer).equals("end")) break;
Puffer = null;
buffer = neues Byte[1024];
}
pis.close();
Puffer = null;
}
Catch (Ausnahme ex)
{
ex.printStackTrace();
}
}
};
thread1.setDaemon(true);
thread2.setDaemon(true);
thread1.start();
thread2.start();
thread1.join();
thread2.join();
}
Thread thread1 = neuer Thread()
{
public void run()
{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
versuchen
{
while(true)
{
String message = br.readLine();
bw.write(Nachricht);
bw.newLine();
bw.flush();
if (message.equals("end")) break;
}
br.close();
pw.close();
bw.close();
}
Catch (Ausnahme ex)
{
ex.printStackTrace();
}
}
};
Thread thread2 = neuer Thread()
{
public void run()
{
String line = null;
versuchen
{
while((line = br.readLine()) != null)
{
System.out.println(line);
if (line.equals("end")) break;
}
br.close();
pr.close();
}
Catch (Ausnahme ex)
{
ex.printStackTrace();
}
}
};
thread1.setDaemon(true);
thread2.setDaemon(true);
thread1.start();
thread2.start();
thread1.join();
thread2.join();
}