4 Methoden zum Schreiben von Multi-Threaded-Code in Java
Multi-Threading ist eine Methode zum Schreiben von Code zum parallelen Ausführen von Aufgaben. Java hat seit den Anfängen von Java 1.0 eine hervorragende Unterstützung für das Schreiben von Multithread-Code. Die jüngsten Verbesserungen von Java haben die Möglichkeiten erweitert, mit denen Code strukturiert werden kann, um Multithreading in Java-Programme zu integrieren.
In diesem Artikel vergleichen wir einige dieser Optionen, damit Sie besser beurteilen können, welche Option für Ihr nächstes Java-Projekt Love GitHub verwendet werden soll. 4 Gründe, warum Sie Ihren Code auf BitBucket Love GitHub hosten sollten? 4 Gründe, warum Sie Ihren Code auf BitBucket hosten sollten Sie müssen sich überlegen, wo Sie Ihren Code speichern möchten. Sie haben wahrscheinlich von GitHub gehört. Das ist nicht überraschend. GitHub wird von Einzelpersonen und Unternehmen verwendet, um Code zu hosten, bei der Dokumentation zusammenzuarbeiten… Lesen Sie mehr t.
Methode 1: Erweitern der Thread-Klasse
Java bietet eine Faden Klasse, die zur Implementierung der erweitert werden kann Lauf() Methode. In dieser run () -Methode implementieren Sie Ihre Aufgabe. Wenn Sie die Aufgabe in einem eigenen Thread starten möchten, können Sie eine Instanz dieser Klasse erstellen und deren Instanz aufrufen Start() Methode. Dadurch wird die Thread-Ausführung gestartet und bis zum Abschluss ausgeführt (oder in einer Ausnahme beendet)..
Hier ist eine einfache Thread-Klasse, die nur für ein angegebenes Intervall inaktiv ist, um einen lang andauernden Vorgang zu simulieren.
public class MyThread erweitert Thread private int sleepFor; public MyThread (int sleepFor) this.sleepFor = sleepFor; @Override public void run () System.out.printf ("[% s] Thread wird gestartet \ n", Thread.currentThread (). ToString ()); try Thread.sleep (this.sleepFor); catch (InterruptedException ex) System.out.printf ("[% s] Thread endet \ n", Thread.currentThread (). toString ());
Erstellen Sie eine Instanz dieser Thread-Klasse, indem Sie ihr die Anzahl der Millisekunden für den Schlaf zuweisen.
MyThread-Worker = neues MyThread (sleepFor);
Starten Sie die Ausführung dieses Worker-Threads, indem Sie die start () -Methode aufrufen. Diese Methode gibt die Kontrolle sofort an den Aufrufer zurück, ohne darauf zu warten, dass der Thread beendet wird.
worker.start (); System.out.printf ("[% s] main thread \ n", Thread.currentThread (). ToString ());
Und hier ist die Ausgabe, wenn dieser Code ausgeführt wird. Es zeigt an, dass die Haupt-Thread-Diagnose gedruckt wird, bevor der Worker-Thread ausgeführt wird.
[Gewinde [Haupt, 5, Haupt]] Hauptgewinde [Gewinde [Gewinde 0,5, Haupt]] Gewindeanfang [Gewinde [Gewinde 0,5, Haupt]] Gewindeende
Da nach dem Starten des Worker-Threads keine weiteren Anweisungen vorhanden sind, wartet der Haupt-Thread, bis der Worker-Thread beendet ist, bevor das Programm beendet wird. Dadurch kann der Arbeitsthread seine Aufgabe abschließen.
Methode 2: Verwenden einer Thread-Instanz mit einer ausführbaren Instanz
Java bietet auch eine Schnittstelle namens Lauffähig die von einer Arbeiterklasse implementiert werden kann, um die Task in ihrer auszuführen Lauf() Methode. Dies ist eine alternative Methode zum Erstellen einer Arbeiterklasse, anstatt die Klasse zu erweitern Faden Klasse (oben beschrieben).
Hier ist die Implementierung der Workerklasse, die jetzt Runnable implementiert, anstatt Thread zu erweitern.
öffentliche Klasse MyThread2 implementiert Runnable // wie oben
Der Vorteil der Implementierung der Runnable-Schnittstelle anstelle der Erweiterung der Thread-Klasse besteht darin, dass die Arbeiterklasse jetzt eine domänenspezifische Klasse innerhalb einer Klassenhierarchie erweitern kann.
Was bedeutet das?
Sagen wir zum Beispiel, Sie haben eine Obst Klasse, die bestimmte generische Merkmale von Früchten implementiert. Nun möchten Sie ein implementieren Papaya Klasse, die bestimmte Fruchtmerkmale spezialisiert. Sie können das tun, indem Sie die Papaya Klasse erweitern die Obst Klasse.
öffentliche Klasse Frucht // Fruchtmerkmale hier öffentliche Klasse Papaya erweitert Frucht // Überschreibungsverhalten der Papaya hier
Angenommen, Sie haben einige zeitaufwendige Aufgaben, die Papaya unterstützen muss, die in einem separaten Thread ausgeführt werden können. Dieser Fall kann behandelt werden, indem die Papaya-Klasse Runnable implementiert und die run () -Methode bereitstellt, in der diese Task ausgeführt wird.
public class Papaya erweitert Fruit implementiert Runnable // überschreibt das Verhalten, das für die Papaya spezifisch ist, hier @Override public void run () // zeitaufwändige Aufgabe hier.
Um den Arbeitsthread zu starten, erstellen Sie eine Instanz der Arbeiterklasse und übergeben diese bei der Erstellung an eine Thread-Instanz. Wenn die start () - Methode des Threads aufgerufen wird, wird die Task in einem separaten Thread ausgeführt.
Papaya Papaya = neue Papaya (); // Eigenschaften setzen und Papaya-Methoden hier aufrufen. Thread Thread = Neuer Thread (Papaya); thread.start ();
Und das ist eine kurze Zusammenfassung, wie ein Runable zum Implementieren einer Task verwendet wird, die in einem Thread ausgeführt wird.
Methode 3: Ausführen einer ausführbaren Version mit ExecutorService
Java bietet ab Version 1.5 eine ExecutorService als neues Paradigma zum Erstellen und Verwalten von Threads innerhalb eines Programms. Es verallgemeinert das Konzept der Thread-Ausführung, indem die Erstellung von Threads weggeblasen wird.
Dies liegt daran, dass Sie Ihre Aufgaben in einem Pool von Threads genauso einfach ausführen können wie einen separaten Thread für jede Aufgabe. Dadurch kann Ihr Programm nachverfolgen und verwalten, wie viele Threads für Worker-Aufgaben verwendet werden.
Angenommen, Sie haben 100 Aufgaben, die auf die Ausführung warten. Wenn Sie einen Thread pro Worker starten (wie oben dargestellt), haben Sie 100 Threads in Ihrem Programm, die an anderen Stellen des Programms zu Engpässen führen könnten. Wenn Sie einen Thread-Pool mit beispielsweise zehn vorab zugewiesenen Threads verwenden, werden Ihre 100 Aufgaben stattdessen von diesen Threads nacheinander ausgeführt, sodass Ihr Programm nicht auf Ressourcen angewiesen ist. Darüber hinaus können diese Thread-Pool-Threads so konfiguriert werden, dass sie sich aufhalten, um zusätzliche Aufgaben für Sie auszuführen.
Ein ExecutorService akzeptiert eine Lauffähig Task (oben erklärt) und führt die Task zu einem geeigneten Zeitpunkt aus. Das einreichen() Die Methode, die die ausführbare Task akzeptiert, gibt eine Instanz einer aufgerufenen Klasse zurück Zukunft, Dadurch kann der Anrufer den Status der Aufgabe verfolgen. Insbesondere die erhalten() Mit dieser Methode kann der Aufrufer warten, bis die Aufgabe abgeschlossen ist (und gegebenenfalls den Rückkehrcode)..
Im folgenden Beispiel erstellen wir einen ExecutorService mit der statischen Methode newSingleThreadExecutor (), Wie der Name schon sagt, wird ein einzelner Thread zum Ausführen von Aufgaben erstellt. Wenn mehr Tasks übergeben werden, während eine Task ausgeführt wird, stellt ExecutorService diese Tasks für die nachfolgende Ausführung in eine Warteschlange.
Die Runable-Implementierung, die wir hier verwenden, ist die gleiche wie oben beschrieben.
ExecutorService esvc = Executors.newSingleThreadExecutor (); Lauffähiger Arbeiter = neues MyThread2 (sleepFor); Zukunft> future = esvc.submit (Arbeiter); System.out.printf ("[% s] main thread \ n", Thread.currentThread (). ToString ()); future.get (); esvc.shutdown ();
Beachten Sie, dass ein ExecutorService ordnungsgemäß heruntergefahren werden muss, wenn er nicht mehr für die Weitergabe von Aufgaben benötigt wird.
Methode 4: Eine aufrufbare Anwendung, die mit ExecutorService verwendet wird
Ab Version 1.5 wurde in Java eine neue Schnittstelle eingeführt Abrufbar. Es ist der älteren Runnable-Schnittstelle ähnlich, mit dem Unterschied, dass die Ausführungsmethode (aufgerufen) wird Anruf() anstatt Lauf()) kann einen Wert zurückgeben. Darüber hinaus kann es auch erklären, dass ein Ausnahme kann geworfen werden.
Ein ExecutorService kann auch als implementierte Tasks akzeptieren Abrufbar und kehrt zurück Zukunft mit dem Wert, den die Methode bei Beendigung zurückgibt.
Hier ist ein Beispiel Mango Klasse, die die erweitert Obst früher definierte Klasse und implementiert die Abrufbar Schnittstelle. Eine kostenintensive und zeitaufwändige Aufgabe wird innerhalb von erledigt Anruf() Methode.
public class Mango erweitert Fruit implementiert Callable public Integer call () // teure Berechnung hier return new Integer (0);
Und hier ist der Code zum Senden einer Instanz der Klasse an einen ExecutorService. Der folgende Code wartet ebenfalls auf den Abschluss der Aufgabe und gibt den Rückgabewert aus.
ExecutorService esvc = Executors.newSingleThreadExecutor (); MyCallable-Worker = new MyCallable (sleepFor); Future Future = esvc.submit (Arbeiter); System.out.printf ("[% s] main thread \ n", Thread.currentThread (). ToString ()); System.out.println ("Aufgabe zurückgegeben:" + future.get ()); esvc.shutdown ();
Was bevorzugen Sie?
In diesem Artikel haben wir einige Methoden zum Schreiben von Multithread-Code in Java kennen gelernt. Diese schließen ein:
- Erweiterung der Faden Klasse ist die grundlegendste und ist seit Java 1.0 verfügbar.
- Wenn Sie eine Klasse haben, die eine andere Klasse in einer Klassenhierarchie erweitern muss, können Sie das implementieren Lauffähig Schnittstelle.
- Eine modernere Einrichtung zum Erstellen von Threads ist das ExecutorService die eine ausführbare Instanz als auszuführende Task akzeptieren kann. Der Vorteil dieser Methode ist, dass Sie einen Thread-Pool für die Taskausführung verwenden können. Ein Thread-Pool hilft bei der Ressourcenschonung, indem er Threads wiederverwendet.
- Schließlich können Sie auch eine Aufgabe erstellen, indem Sie die Abrufbar Schnittstelle und Übergabe der Aufgabe an einen ExecutorService.
Welche dieser Optionen werden Ihrer Meinung nach in Ihrem nächsten Projekt verwendet? Lass es uns in den Kommentaren wissen.
Erfahren Sie mehr über: Java.