Heim  >  Artikel  >  Java  >  Was ist der Nutzen von Java-Threads?

Was ist der Nutzen von Java-Threads?

(*-*)浩
(*-*)浩Original
2019-05-08 17:05:444167Durchsuche

In diesem Tutorial werden die Grundlagen von Threads untersucht – was sie sind, warum sie nützlich sind und wie man mit dem Schreiben einfacher Programme beginnt, die Threads verwenden. (Empfohlener Kurs: Java Video Tutorial)

Was ist ein Thread?

Fast jedes Betriebssystem unterstützt das Konzept von Prozessen – Programmen, die etwas voneinander isoliert sind und unabhängig voneinander laufen.

Threading ist ein Tool, das die Koexistenz mehrerer Aktivitäten in einem Prozess ermöglicht. Die meisten modernen Betriebssysteme unterstützen Threads, und das Konzept der Threads gibt es in verschiedenen Formen schon seit vielen Jahren. Java war die erste große Programmiersprache, die Threads explizit in die Sprache selbst einbezog; sie betrachtete Threading nicht als Werkzeug des zugrunde liegenden Betriebssystems.

Manchmal werden Threads auch als Lightweight-Prozesse bezeichnet. Genau wie Prozesse sind Threads unabhängige, gleichzeitige Ausführungspfade im Programm. Jeder Thread verfügt über seinen eigenen Stapel, seinen eigenen Programmzähler und seine eigenen lokalen Variablen. Allerdings sind Threads innerhalb eines Prozesses weniger voneinander isoliert als separate Prozesse. Sie teilen sich Speicher, Dateihandles und andere Zustände, die jeder Prozess haben sollte.

Ein Prozess kann mehrere Threads unterstützen, die scheinbar gleichzeitig ausgeführt werden, aber nicht miteinander synchronisiert sind. Mehrere Threads in einem Prozess teilen sich denselben Speicheradressraum, was bedeutet, dass sie auf dieselben Variablen und Objekte zugreifen können und Objekte aus demselben Heap zuweisen. Obwohl dies den Informationsaustausch zwischen Threads erleichtert, müssen Sie darauf achten, dass sie andere Threads im selben Prozess nicht beeinträchtigen.

Java-Threading-Tools und API sind täuschend einfach. Allerdings ist es nicht ganz einfach, komplexe Programme zu schreiben, die Threads effektiv nutzen. Da mehrere Threads im selben Speicherbereich nebeneinander existieren und dieselben Variablen gemeinsam nutzen, müssen Sie darauf achten, dass sich Ihre Threads nicht gegenseitig stören.

Jedes Java-Programm verwendet Threads

Jedes Java-Programm hat mindestens einen Thread – den Haupt-Thread. Wenn ein Java-Programm startet, erstellt die JVM den Hauptthread und ruft in diesem Thread die Methode main() des Programms auf.

Die JVM erstellt auch andere Threads, die Sie normalerweise nicht sehen – zum Beispiel Threads im Zusammenhang mit Garbage Collection, Objektbeendigung und anderen JVM-Verwaltungsaufgaben. Andere Tools erstellen ebenfalls Threads, etwa AWT (Abstract Windowing Toolkit) oder Swing UI Toolkit, Servlet-Container, Anwendungsserver und RMI (Remote Method Invocation).

Warum Threads verwenden?

Es gibt viele Gründe, Threads in Java-Programmen zu verwenden. Wenn Sie Swing-, Servlet-, RMI- oder Enterprise JavaBeans (EJB)-Technologie verwenden, bemerken Sie möglicherweise nicht, dass Sie bereits Threads verwenden.

Einige Gründe für die Verwendung von Threads sind, dass sie helfen können:

Machen Sie die Benutzeroberfläche reaktionsfähiger

Nutzen Sie die Vorteile von Multiprozessorsystemen

Vereinfachen Sie die Modellierung

Asynchrone oder Hintergrundverarbeitung durchführen

Reaktionsfähigere Benutzeroberfläche

Ereignisgesteuerte UI-Toolkits (wie AWT und Swing) verfügen über einen Ereignisthread, der die Verarbeitung übernimmt UI-Ereignisse wie Tastenanschläge oder Mausklicks.

AWT- und Swing-Programme verbinden Ereignis-Listener mit UI-Objekten. Diese Listener werden benachrichtigt, wenn ein bestimmtes Ereignis eintritt, beispielsweise das Klicken auf eine Schaltfläche. Ereignis-Listener werden im AWT-Ereignisthread aufgerufen.

Wenn der Ereignis-Listener eine langwierige Aufgabe ausführen soll, beispielsweise die Rechtschreibprüfung in einem großen Dokument, ist der Ereignis-Thread damit beschäftigt, die Rechtschreibprüfung auszuführen, sodass vor dem Ereignis-Listener keine weitere Verarbeitung durchgeführt werden kann ist abgeschlossen. Dies kann dazu führen, dass das Programm hängen bleibt und der Benutzer verwirrt ist.

Um eine verzögerte UI-Reaktion zu vermeiden, sollte der Ereignis-Listener längere Aufgaben in einen anderen Thread stellen, damit der AWT-Thread während der Ausführung der Aufgabe weiterhin UI-Ereignisse verarbeiten kann (einschließlich des Abbruchs der Ausführung der Aufgabe). Anfragen für lang laufende Aufgaben).

Einsatz von Multiprozessorsystemen

Multiprozessorsysteme (MP) sind häufiger als in der Vergangenheit. Bisher waren sie nur in großen Rechenzentren und wissenschaftlichen Rechenanlagen zu finden. Viele Low-End-Serversysteme – und sogar einige Desktop-Systeme – verfügen heutzutage über mehrere Prozessoren.

Moderne Betriebssysteme, einschließlich Linux, Solaris und Windows NT/2000, können die Vorteile mehrerer Prozessoren nutzen und Threads so planen, dass sie auf jedem verfügbaren Prozessor ausgeführt werden.

Die Grundeinheit der Planung ist normalerweise ein Thread. Wenn ein Programm nur einen aktiven Thread hat, kann es jeweils nur auf einem Prozessor ausgeführt werden. Wenn ein Programm über mehrere aktive Threads verfügt, können mehrere Threads gleichzeitig geplant werden. In einem gut gestalteten Programm kann die Verwendung mehrerer Threads den Programmdurchsatz und die Leistung verbessern.

Vereinfachte Modellierung

In einigen Fällen kann die Verwendung von Threads das Schreiben und Warten von Programmen vereinfachen. Stellen Sie sich eine Simulationsanwendung vor, in der Sie Interaktionen zwischen mehreren Entitäten simulieren möchten. Indem man jeder Entität einen eigenen Thread gibt, können viele Simulationen und Modellierungsanwendungen erheblich vereinfacht werden.

Ein weiteres Beispiel für die Verwendung separater Threads zur Vereinfachung eines Programms ist, wenn eine Anwendung über mehrere unabhängige ereignisgesteuerte Komponenten verfügt. Beispielsweise könnte eine Anwendung über eine Komponente verfügen, die die Sekunden nach einem Ereignis herunterzählt und die Bildschirmanzeige aktualisiert. Anstatt eine Hauptschleife zu haben, die regelmäßig die Zeit überprüft und die Anzeige aktualisiert, ist es einfacher und weniger fehleranfällig, einen Thread nichts tun zu lassen und bis eine bestimmte Zeit später zu schlafen, wenn der Bildschirmzähler aktualisiert wird. Auf diese Weise muss sich der Hauptthread überhaupt nicht um den Timer kümmern.

Asynchrone oder Hintergrundverarbeitung

Eine Serveranwendung erhält Eingaben von einer Remote-Quelle wie einem Socket. Wenn beim Lesen aus einem Socket derzeit keine Daten verfügbar sind, wird der Aufruf von SocketInputStream.read() blockiert, bis Daten verfügbar sind.

Wenn ein Single-Threaded-Programm von einem Socket liest und die Entität am anderen Ende des Sockets keine Daten sendet, wartet das Programm einfach ewig, ohne eine andere Verarbeitung durchzuführen. Stattdessen kann ein Programm den Socket abfragen, um zu sehen, ob Daten verfügbar sind. Dies wird jedoch aufgrund der Leistungseinbußen im Allgemeinen nicht verwendet.

Wenn Sie jedoch einen Thread zum Lesen aus dem Socket erstellen, kann der Hauptthread andere Aufgaben ausführen, während dieser Thread auf Eingaben vom Socket wartet. Sie können sogar mehrere Threads erstellen, sodass Sie gleichzeitig von mehreren Sockets lesen können. Auf diese Weise werden Sie schnell benachrichtigt, wenn Daten verfügbar sind (da der wartende Thread aktiviert wird), ohne häufig abfragen zu müssen, ob Daten verfügbar sind. Code, der Threads verwendet, um auf Sockets zu warten, ist außerdem einfacher und weniger fehleranfällig als Polling.

Einfach, aber manchmal riskant

Obwohl Java-Threading-Tools sehr einfach zu verwenden sind, gibt es einige Risiken, die Sie beim Erstellen von Multithread-Programmen vermeiden sollten .

Wenn mehrere Threads auf dasselbe Datenelement zugreifen (z. B. ein statisches Feld, ein Instanzfeld eines global zugänglichen Objekts oder eine gemeinsam genutzte Sammlung), müssen Sie sicherstellen, dass sie ihren Zugriff auf die Daten so koordinieren Sie alle können die Daten konsistent sehen, ohne die Änderungen des anderen zu beeinträchtigen. Um diesen Zweck zu erreichen, stellt die Java-Sprache zwei Schlüsselwörter bereit: synchronisiert und flüchtig. Wir werden uns später in diesem Tutorial mit dem Zweck und der Bedeutung dieser Schlüsselwörter befassen.

Wenn Sie von mehreren Threads aus auf eine Variable zugreifen, müssen Sie sicherstellen, dass der Zugriff ordnungsgemäß synchronisiert ist. Bei einfachen Variablen kann es ausreichend sein, die Variable als flüchtig zu deklarieren, in den meisten Fällen ist jedoch eine Synchronisierung erforderlich.

Wenn Sie die Synchronisierung zum Schutz des Zugriffs auf eine gemeinsam genutzte Variable verwenden möchten, müssen Sie sicherstellen, dass die Synchronisierung überall im Programm verwendet wird, wo auf die Variable zugegriffen wird.

Übertreiben Sie es nicht

Während Threads viele Arten von Anwendungen erheblich vereinfachen können, kann eine übermäßige Verwendung von Threads die Leistung und Wartbarkeit eines Programms gefährden. Der Thread hat Ressourcen verbraucht. Daher ist die Anzahl der Threads, die ohne Leistungseinbußen erstellt werden können, begrenzt.

Besonders auf einem Einprozessorsystem führt die Verwendung mehrerer Threads nicht dazu, dass Programme, die hauptsächlich CPU-Ressourcen verbrauchen, schneller laufen.

Beispiel: Verwenden Sie einen Thread für das Timing und einen anderen Thread für die Arbeit

Das folgende Beispiel verwendet zwei Threads, einen für das Timing und einen für die Ausführung. Tatsächliche Arbeit. Der Hauptthread verwendet einen sehr einfachen Algorithmus zur Berechnung von Primzahlen.

Bevor es startet, erstellt und startet es einen Timer-Thread, der zehn Sekunden lang schläft, und setzt dann ein Flag, das der Haupt-Thread überprüft. Nach zehn Sekunden stoppt der Hauptthread. Beachten Sie, dass das Shared Flag als flüchtig deklariert ist.

/**
 * CalculatePrimes -- calculate as many primes as we can in ten seconds 
 */ 
 
public class CalculatePrimes extends Thread {
 
    public static final int MAX_PRIMES = 1000000;
    public static final int TEN_SECONDS = 10000;
 
    public volatile boolean finished = false;
 
    public void run() {
        int[] primes = new int[MAX_PRIMES];
        int count = 0;
 
        for (int i=2; count<MAX_PRIMES; i++) {
 
            // Check to see if the timer has expired
            if (finished) {
                break;
            }
 
            boolean prime = true;
            for (int j=0; j<count; j++) {
                if (i % primes[j] == 0) {
                    prime = false;
                    break;
                }
            }
 
            if (prime) {
                primes[count++] = i;
                System.out.println("Found prime: " + i);
            }
        }
    }
 
    public static void main(String[] args) {
        CalculatePrimes calculator = new CalculatePrimes();
        calculator.start();
        try {
            Thread.sleep(TEN_SECONDS);
        }
        catch (InterruptedException e) {
            // fall through
        }
 
        calculator.finished = true;
    }
}

Zusammenfassung

Die Java-Sprache umfasst leistungsstarke, in die Sprache integrierte Threading-Funktionen. Sie können Threading-Tools verwenden, um:

die Reaktionsfähigkeit von GUI-Anwendungen zu erhöhen

die Vorteile von Multiprozessorsystemen zu nutzen

die Programmlogik zu vereinfachen, wenn das Programm über mehrere unabhängige Einheiten verfügt

Führen Sie blockierende E/A durch, ohne das gesamte Programm zu blockieren

Bei der Verwendung mehrerer Threads muss darauf geachtet werden, die Regeln für die gemeinsame Nutzung von Daten zwischen Threads zu befolgen, die wir unter „Freigabe“ besprechen. Diese Regeln werden in besprochen Zugriff auf Daten. Alle diese Regeln laufen auf ein Grundprinzip hinaus: Vergessen Sie nicht, zu synchronisieren.

Das obige ist der detaillierte Inhalt vonWas ist der Nutzen von Java-Threads?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn