Java Multithreading erklärt: Konzepte, Lebenszyklus und praktische Code-Beispiele
Java-Anwendungen müssen oft mehrere Aufgaben gleichzeitig ausführen. Dieses Tutorial führt Sie durch Single-Threaded- versus Multi-Threaded-Ausführung, den Lebenszyklus eines Threads, Synchronisationstechniken und praxisnahe Code-Beispiele, die jedes Konzept veranschaulichen.
Was ist ein Single Thread?
Ein Single Thread in Java ist die kleinste Ausführungseinheit. Die Java-Laufzeit erstellt einen User Thread beim Anwendungsstart, und Sie können zusätzliche User- oder Daemon Threads nach Bedarf hinzufügen. Daemon-Threads laufen im Hintergrund und verhindern nicht, dass die JVM beendet wird.
Beispiel für einen Single Thread:
package demotest;
public class GuruThread {
public static void main(String[] args) {
System.out.println("Single Thread");
}
}
Vorteile der Single-Threaded-Ausführung:
- Minimaler Overhead – nur ein Ausführungskontext wird verwaltet.
- Vereinfachtes Debugging und Wartung.
Was ist Multithreading in Java?
Multithreading erlaubt zwei oder mehr Threads, parallel zu laufen und maximiert die CPU-Auslastung. Threads teilen sich denselben Speicherplatz, sodass Kontextwechsel schnell sind und der Speicherverbrauch niedrig bleibt.
Beispiel für die Erstellung zweier paralleler Threads:
package demotest;
public class GuruThread1 implements Runnable {
public static void main(String[] args) {
Thread guruThread1 = new Thread("Guru1");
Thread guruThread2 = new Thread("Guru2");
guruThread1.start();
guruThread2.start();
System.out.println("Thread names are following:");
System.out.println(guruThread1.getName());
System.out.println(guruThread2.getName());
}
@Override
public void run() {
// Thread-Logik hier
}
}
Vorteile von Multithreading:
- Nicht-blockierende UI und Hintergrundverarbeitung.
- Resilienz – eine Exception in einem Thread stoppt andere nicht.
Thread-Lebenszyklus in Java
Der Thread-Lebenszyklus besteht aus fünf verschiedenen Zuständen:
- New – Thread ist instanziiert, aber nicht gestartet.
- Runnable – Thread wurde gestartet und ist bereit zur Ausführung.
- Running – Thread führt aktiv aus.
- Waiting – Thread ist suspendiert, bis ein bestimmtes Ereignis eintritt.
- Dead – Thread hat die Ausführung beendet.
Wichtige Thread-Methoden
| Methode | Beschreibung |
|---|---|
| start() | Beginnt Thread-Ausführung; JVM ruft run() auf. |
| sleep(long milliseconds) | Pausiert den aktuellen Thread für die angegebene Dauer. |
| getName() | Gibt den Namen des Threads zurück. |
| setPriority(int newPriority) | Justiert Thread-Priorität (1-10). |
| yield() | Schlägt dem Scheduler vor, den aktuellen Thread zu pausieren. |
Praktisches Thread-Beispiel
Nachfolgend ein prägnantes Beispiel, das Thread-Erstellung, Prioritätsanpassung und Sleep demonstriert.
package demotest;
public class ThreadExample1 implements Runnable {
@Override
public void run() {
// Thread-Arbeit hier
}
public static void main(String[] args) {
Thread guruThread1 = new Thread();
guruThread1.start();
try {
Thread.sleep(1000); // 1 Sekunde pausieren
} catch (InterruptedException e) {
e.printStackTrace();
}
guruThread1.setPriority(1);
System.out.println(guruThread1.getPriority());
System.out.println("Thread Running");
}
}
Ausgabe-Beispiel:
Thread-Synchronisation
Wenn mehrere Threads auf gemeinsame Ressourcen zugreifen, stellt Synchronisation Datenkonsistenz sicher. In Java können Sie kritische Abschnitte mit dem synchronized-Schlüsselwort umschließen, was exklusiven Zugriff garantiert.
synchronized(object) {
// synchronisierter Block
}
Fortgeschrittenes Multithreading-Beispiel
Nachfolgend ein ausführlicheres Beispiel, das zwei Threads erstellt, die jeweils ihren Namen und einen Zähler mit einer Sekunde Verzögerung ausgeben.
package demotest;
public class GuruThread2 {
public static void main(String[] args) {
GuruThread3 threadGuru1 = new GuruThread3("guru1");
threadGuru1.start();
GuruThread3 threadGuru2 = new GuruThread3("guru2");
threadGuru2.start();
}
}
class GuruThread3 implements Runnable {
private Thread guruthread;
private String guruname;
GuruThread3(String name) {
this.guruname = name;
}
@Override
public void run() {
System.out.println("Thread running " + guruname);
for (int i = 0; i < 4; i++) {
System.out.println(i);
System.out.println(guruname);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("Thread has been interrupted");
}
}
}
public void start() {
System.out.println("Thread started");
if (guruthread == null) {
guruthread = new Thread(this, guruname);
guruthread.start();
}
}
}
Typische Ausgabe (illustriert im begleitenden Bild):
Zusammenfassung
- Multithreading befreit die Anwendung von blockierenden Aufrufen und ermöglicht parallele Operationen.
- Der Thread-Lebenszyklus – New, Runnable, Running, Waiting, Dead – definiert die Zustände, die ein Thread durchläuft.
- Synchronisation ist essenziell, wenn Threads Daten teilen, um Race Conditions zu verhindern.
- Praktische Code-Beispiele festigen das Verständnis von Thread-Erstellung, Lebenszyklus-Management und Synchronisation.
Java
- Java Hello World: Ihr erstes Programm
- C++-Funktionen erklärt: Mit praktischen Code-Beispielen
- C# Collections meistern: Praktisches Tutorial mit Real-World-Beispielen
- Java String.indexOf() meistern: Substrings finden & praktische Beispiele
- Java String.charAt(): Syntax, Rückgabetyp, Exceptions und praktisches Beispiel
- Java String compareTo() meistern: Syntax, Anwendungsfälle und praktische Beispiele
- Konstruktor-Überladung in Java – Erklärt mit praktischen Code-Beispielen
- Java-Programm zur Prüfung, ob eine Zahl prim ist
- Insertion Sort Algorithmus in Java: Klares Beispiel & Schritt-für-Schritt-Anleitung
- Selection Sort in Java: Schritt-für-Schritt-Beispiel & Vollständiger Code