Industrielle Fertigung
Industrielles Internet der Dinge | Industrielle Materialien | Gerätewartung und Reparatur | Industrielle Programmierung |
home  MfgRobots >> Industrielle Fertigung >  >> Industrial programming >> Java

Java Multithreading meistern: Effiziente Nebenläufigkeitsprogrammierung

Java ist eine multithreaded Programmiersprache, was bedeutet, dass wir mehrthreadige Programme mit Java entwickeln können. Ein mehrthreadiges Programm enthält zwei oder mehr Teile, die gleichzeitig ausgeführt werden können und jeweils eine andere Aufgabe zur gleichen Zeit bewältigen – was eine optimale Nutzung der verfügbaren Ressourcen ermöglicht, besonders wenn Ihr Computer über mehrere CPUs verfügt.

Per Definition ist Multitasking der Zustand, bei dem mehrere Prozesse gemeinsame Verarbeitungsressourcen wie eine CPU teilen. Multithreading erweitert das Konzept des Multitasking auf Anwendungen, bei denen Sie spezifische Operationen innerhalb einer einzelnen Anwendung in einzelne Threads unterteilen können. Jeder dieser Threads kann parallel laufen. Das Betriebssystem teilt die Verarbeitungszeit nicht nur zwischen verschiedenen Anwendungen auf, sondern auch zwischen jedem Thread innerhalb einer Anwendung.

Multithreading ermöglicht es Ihnen, Code so zu schreiben, dass mehrere Aktivitäten gleichzeitig im selben Programm ablaufen können.

Lebenszyklus eines Threads

Ein Thread durchläuft verschiedene Phasen in seinem Lebenszyklus. Zum Beispiel wird ein Thread geboren, gestartet, läuft und stirbt dann. Die folgende Abbildung zeigt den vollständigen Lebenszyklus eines Threads.

Java Multithreading meistern: Effiziente Nebenläufigkeitsprogrammierung

Dies sind die Phasen des Lebenszyklus:

Thread-Prioritäten

Jeder Java-Thread hat eine Priorität, die dem Betriebssystem hilft, die Reihenfolge festzulegen, in der Threads geplant werden.

Java-Thread-Prioritäten liegen im Bereich zwischen MIN_PRIORITY (Konstante 1) und MAX_PRIORITY (Konstante 10). Standardmäßig erhält jeder Thread die Priorität NORM_PRIORITY (Konstante 5).

Threads mit höherer Priorität sind für ein Programm wichtiger und sollten vor Threads mit niedrigerer Priorität Prozessorzeit erhalten. Allerdings können Thread-Prioritäten die Ausführungsreihenfolge nicht garantieren und sind stark plattformabhängig.

Thread durch Implementieren des Runnable-Interfaces erstellen

Wenn Ihre Klasse als Thread ausgeführt werden soll, können Sie dies erreichen, indem Sie das Runnable-Interface implementieren. Sie müssen drei grundlegende Schritte befolgen:

Schritt 1

Als ersten Schritt müssen Sie die run()-Methode implementieren, die vom Runnable-Interface bereitgestellt wird. Diese Methode stellt den Einstiegspunkt für den Thread dar und Sie platzieren Ihre komplette Geschäftslogik in dieser Methode. Folgende ist die einfache Syntax der run()-Methode:

public void run()

Schritt 2

Als zweiten Schritt instanziieren Sie ein Thread-Objekt mit dem folgenden Konstruktor:

Thread(Runnable threadObj, String threadName);

Wobei threadObj eine Instanz einer Klasse ist, die das Runnable-Interface implementiert, und threadName der Name ist, der dem neuen Thread gegeben wird.

Schritt 3

Sobald ein Thread-Objekt erstellt wurde, können Sie es durch Aufrufen der start()-Methode starten, die einen Aufruf der run()-Methode ausführt. Folgende ist die einfache Syntax der start()-Methode:

void start();

Beispiel

Hier ist ein Beispiel, das einen neuen Thread erstellt und startet:

class RunnableDemo implements Runnable {
    private Thread t;
    private String threadName;

    RunnableDemo(String name) {
        threadName = name;
        System.out.println("Erstelle " + threadName);
    }

    public void run() {
        System.out.println("Führe aus " + threadName);
        try {
            for (int i = 4; i > 0; i--) {
                System.out.println("Thread: " + threadName + ", " + i);
                // Thread schlafen lassen
                Thread.sleep(50);
            }
        } catch (InterruptedException e) {
            System.out.println("Thread " + threadName + " unterbrochen.");
        }
        System.out.println("Thread " + threadName + " beendet.");
    }

    public void start() {
        System.out.println("Starte " + threadName);
        if (t == null) {
            t = new Thread(this, threadName);
            t.start();
        }
    }
}

public class TestThread {
    public static void main(String args[]) {
        RunnableDemo R1 = new RunnableDemo("Thread-1");
        R1.start();
        RunnableDemo R2 = new RunnableDemo("Thread-2");
        R2.start();
    }
}

Ausgabe

Erstelle Thread-1
Starte Thread-1
Erstelle Thread-2
Starte Thread-2
Führe aus Thread-1
Thread: Thread-1, 4
Führe aus Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 beendet.
Thread Thread-2 beendet.

Thread durch Erweitern der Thread-Klasse erstellen

Der zweite Weg, einen Thread zu erstellen, besteht darin, eine neue Klasse zu erstellen, die die Thread-Klasse erweitert. Dieser Ansatz bietet mehr Flexibilität bei der Behandlung mehrerer Threads, die mit den in der Thread-Klasse verfügbaren Methoden erstellt wurden.

Schritt 1

Sie müssen die run()-Methode überschreiben, die in der Thread-Klasse verfügbar ist. Diese Methode stellt den Einstiegspunkt für den Thread dar. Syntax:

public void run()

Schritt 2

Sobald das Thread-Objekt erstellt ist, können Sie es durch Aufrufen der start()-Methode starten. Syntax:

void start();

Beispiel

class ThreadDemo extends Thread {
    private Thread t;
    private String threadName;

    ThreadDemo(String name) {
        threadName = name;
        System.out.println("Erstelle " + threadName);
    }

    public void run() {
        System.out.println("Führe aus " + threadName);
        try {
            for (int i = 4; i > 0; i--) {
                System.out.println("Thread: " + threadName + ", " + i);
                Thread.sleep(50);
            }
        } catch (InterruptedException e) {
            System.out.println("Thread " + threadName + " unterbrochen.");
        }
        System.out.println("Thread " + threadName + " beendet.");
    }

    public void start() {
        System.out.println("Starte " + threadName);
        if (t == null) {
            t = new Thread(this, threadName);
            t.start();
        }
    }
}

public class TestThread {
    public static void main(String args[]) {
        ThreadDemo T1 = new ThreadDemo("Thread-1");
        T1.start();
        ThreadDemo T2 = new ThreadDemo("Thread-2");
        T2.start();
    }
}

Wichtige Thread-Methoden

Die folgende Liste zeigt die wichtigsten Methoden der Thread-Klasse:

Nr.Methode & Beschreibung
1public void start() – Startet den Thread in einem separaten Ausführungspfad und ruft run() auf.
2public void run() – Wird auf dem Runnable-Objekt aufgerufen, falls der Thread mit einem separaten Runnable-Target instanziiert wurde.
3public final void setName(String name) – Ändert den Namen des Thread-Objekts. Es gibt auch getName() zum Abrufen.
4public final void setPriority(int priority) – Setzt die Priorität (Werte 1-10).
5public final void setDaemon(boolean on) – Markiert den Thread als Daemon-Thread.
6public final void join(long millisec) – Blockiert den aktuellen Thread, bis der zweite Thread endet oder die Zeit abläuft.
7public void interrupt() – Unterbricht den Thread, falls er blockiert war.
8public final boolean isAlive() – Gibt true zurück, wenn der Thread lebt (nach start() bis vor Beendigung).

Die folgenden Methoden sind statisch und operieren auf dem aktuell laufenden Thread:

Nr.Methode & Beschreibung
1public static void yield() – Gibt die CPU an andere Threads gleicher Priorität ab.
2public static void sleep(long millisec) – Blockiert den aktuellen Thread für mindestens die angegebenen Millisekunden.
3public static boolean holdsLock(Object x) – Prüft, ob der aktuelle Thread den Lock auf dem gegebenen Objekt hält.
4public static Thread currentThread() – Gibt Referenz auf den aktuell laufenden Thread zurück.
5public static void dumpStack() – Druckt Stack-Trace für Debugging.

Beispiel: ThreadClassDemo

// DisplayMessage.java
public class DisplayMessage implements Runnable {
    private String message;
    public DisplayMessage(String message) { this.message = message; }
    public void run() {
        while(true) { System.out.println(message); }
    }
}

// GuessANumber.java
public class GuessANumber extends Thread {
    private int number;
    public GuessANumber(int number) { this.number = number; }
    public void run() {
        int counter = 0, guess = 0;
        do {
            guess = (int) (Math.random() * 100 + 1);
            System.out.println(this.getName() + " ratet " + guess);
            counter++;
        } while(guess != number);
        System.out.println("** Richtig! " + this.getName() + " in " + counter + " Versuchen.**");
    }
}

// ThreadClassDemo.java
public class ThreadClassDemo {
    public static void main(String[] args) {
        Runnable hello = new DisplayMessage("Hallo");
        Thread thread1 = new Thread(hello);
        thread1.setDaemon(true);
        thread1.setName("hallo");
        System.out.println("Starte hallo-Thread...");
        thread1.start();

        Runnable bye = new DisplayMessage("Tschüss");
        Thread thread2 = new Thread(bye);
        thread2.setPriority(Thread.MIN_PRIORITY);
        thread2.setDaemon(true);
        System.out.println("Starte tschüss-Thread...");
        thread2.start();

        System.out.println("Starte thread3...");
        Thread thread3 = new GuessANumber(27);
        thread3.start();
        try { thread3.join(); } catch (InterruptedException e) { System.out.println("Thread unterbrochen."); }

        System.out.println("Starte thread4...");
        Thread thread4 = new GuessANumber(75);
        thread4.start();
        System.out.println("main() endet...");
    }
}

Wichtige Java-Multithreading-Konzepte

Bei der Multithreading-Programmierung in Java sollten Sie folgende Konzepte beherrschen:

Java

  1. Java Operatoren meistern: Typen, Syntax und praktische Beispiele
  2. Java Kommentare: Typen, Verwendung und Best Practices
  3. Java Enhanced For-Schleife meistern: Syntax, Beispiele und Best Practices
  4. Java Strings meistern: Erstellung, Methoden und Best Practices
  5. Java-Schnittstellen meistern: Konzepte, Implementierung und Best Practices
  6. Java anonyme innere Klassen meistern: Definition, Syntax und praktische Beispiele
  7. Java Try-With-Resources meistern: Automatisches Ressourcenmanagement erklärt
  8. Java Annotations erklärt: Typen, Platzierung und praktische Beispiele
  9. Java Assertions: Praktischer Leitfaden zur Fehlererkennung und Code-Reliabilität
  10. Java Vector verstehen: Verwendung, Funktionen und Vergleich mit ArrayList