English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Java Grund教程

Java Flow Control

Java Array

Java objektorientiert (I)

Java objektorientiert (II)

Java objektorientiert (III)

Java Ausnahmebehandlung

Java Liste (List)

Java Queue (Warteschlange)

Java Map-Kollektion

Java Set-Kollektion

Java Eingabe-Ausgabe (I/O)

Java Reader/Writer

Andere Themen von Java

Java Multithreading-Programmierung

Java bietet eingebaute Unterstützung für Mehrfachthread-Programmierung Ein Thread bezieht sich auf einen einzigen Abfolgekontrollfluss in einem Prozess, in einem Prozess können mehrere Threads gleichzeitig ablaufen, die verschiedene Aufgaben parallel ausführen

Mehrfach threading ist eine spezielle Form von Mehrfacharbeit, aber es verwendet weniger Ressourcen

Hier wird ein weiterer Begriff definiert, der mit Threads in Verbindung steht - Ein Prozess umfasst den vom Betriebssystem zugewiesenen Speicherbereich und enthält eine oder mehrere Threads. Ein Thread kann nicht unabhängig existieren, er muss Teil eines Prozesses sein. Ein Prozess läuft bis alle nicht-dienstlichen Threads beendet sind, bevor er beendet werden kann.

Multithreading can meet the needs of programmers to write efficient programs to fully utilize the CPU.

A thread's life cycle

A thread is a dynamic execution process, and it also has a process from birth to death.

The following diagram shows the complete life cycle of a thread.

  • New state:

    using new keyword and Thread After a class or its subclass creates a thread object, the thread object is in the new state. It remains in this state until the program start() this thread.

  • Ready state:

    After a thread object calls the start() method, the thread enters the ready state. Threads in the ready state are in the ready queue, waiting for the scheduler in the JVM to schedule them.

  • Running state:

    If a thread in the ready state acquires CPU resources, it can execute run(),at this point, the thread is in the running state. Threads in the running state are the most complex, as they can change to blocked, ready, and terminated states.

  • Blocked state:

    If a thread executes methods such as sleep (sleep), suspend (suspend), and loses the resources it occupies, the thread will enter a blocked state from the running state. It can return to the ready state after the sleep time has elapsed or after obtaining device resources. It can be divided into three types:

    • Waiting blocking: A thread in the running state executes the wait() method, causing the thread to enter a waiting blocked state.

    • Synchronized blocking: The thread fails to acquire the synchronized lock (because the lock is held by another thread).

    • Other blocking: Through calling the thread's sleep() or join() methods, an I/O When a request is made, the thread enters a blocked state. When the sleep() state times out, the join() waits for the thread to terminate or times out, or I/O The task is completed, and the thread returns to the ready state.

  • Terminated state:

    When a thread in a running state completes a task or other termination conditions occur, the thread switches to a terminated state.

Thread priority

Each Java thread has a priority, which helps the operating system determine the scheduling order of threads.

The priority of Java threads is an integer with a value range of 1 (Thread.MIN_PRIORITY ) - 10 (Thread.MAX_PRIORITY )。

By default, each thread is assigned a priority NORM_PRIORITY(5)。

Threads with higher priority are more important for the program and should be allocated processor resources before threads with lower priority. However, thread priority cannot guarantee the execution order of threads and is highly dependent on the platform.

创建一个线程

Ein Thread wird erstellt

  • Java bietet drei Methoden zur Erstellung von Threads:

  • Durch die Implementierung des Runnable-Interfaces;

  • Durch die Vererbung der Thread-Klasse selbst;

Durch Callable und Future wird ein Thread erstellt

Durch die Implementierung des Runnable-Interfaces wird ein Thread erstellt

Die einfachste Methode zur Erstellung eines Threads besteht darin, eine Klasse zu erstellen, die das Runnable-Interface implementiert.

Um das Runnable-Interface zu implementieren, muss eine Klasse nur eine Methodenaufruf run() ausführen, wie folgt deklariert:

public void run()

Sie können diese Methode überschreiben, wichtig ist zu verstehen, dass run() andere Methoden aufrufen, andere Klassen verwenden und Variablen deklarieren kann, wie die Hauptthread.

Nachdem eine Klasse implementiert wurde, die das Runnable-Interface implementiert, können Sie in der Klasse ein Beispiel für ein Thread-Objekt erstellen.

Thread definiert mehrere Konstruktoren, der folgende ist der am häufigsten verwendete:

Thread(Runnable threadOb, String threadName);

Hierbei ist threadOb ein Beispiel für eine Klasse, die das Runnable-Interface implementiert, und threadName gibt den Namen des neuen Threads an.

Nachdem der neue Thread erstellt wurde, wird er erst ausgeführt, wenn Sie die start() -Methode aufrufen.

void start();

Hier ist ein Beispiel zur Erstellung eines Threads und zur Ausführung desselben:
   private Thread t;
   private String threadName;
   
   class RunnableDemo implements Runnable {
      threadName = name;
      System.out.println("Creating " +  threadName);
   }
   
   public void run() {
      System.out.println("Running " +  threadName);
      try {
         for (int i = 4; i > 0; i--) {
            System.out.println("Thread: " + threadName + ", " + i);
            // Let the thread sleep for a while
            Thread.sleep(50);
         }
      } catch (InterruptedException e) {
         System.out.println("Thread " +  threadName + " interrupted.");
      }
      System.out.println("Thread " +  threadName + " exiting.");
   }
   
   public void start() {
      System.out.println("Starting " +  threadName);
      if (t == null) {
         t = new Thread(this, threadName);
         t.start();
      }
   }
}
 
public class TestThread {
 
   public static void main(String args[]) {
      RunnableDemo(String name) {1 RunnableDemo R-1);
      R = new RunnableDemo("Thread1.start();
      
      RunnableDemo(String name) {2 RunnableDemo R-2);
      R = new RunnableDemo("Thread2.start();
   }   
}

The compilation and running results of the above program are as follows:

Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running 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 exiting.
Thread Thread-2 exiting.

Durch die Vererbung von Thread wird ein Thread erstellt

Eine zweite Methode zur Erstellung eines Threads besteht darin, eine neue Klasse zu erstellen, die die Thread-Klasse ableitet, und dann ein Beispiel dieser Klasse zu erstellen.

Die abgeleitete Klasse muss die run() -Methode überschreiben, die den Einstiegspunkt für den neuen Thread ist. Es muss auch die start() -Methode aufgerufen werden, um sie auszuführen.

Diese Methode wird als eine Art von Multithreading-Implementierung aufgeführt, ist aber im Wesentlichen auch ein Beispiel für die Implementierung des Runnable-Interfaces.

class ThreadDemo extends Thread {
   private Thread t;
   private String threadName;
   
   ThreadDemo(String name) {
      threadName = name;
      System.out.println("Creating " +  threadName);
   }
   
   public void run() {
      System.out.println("Running " +  threadName);
      try {
         for (int i = 4; i > 0; i--) {
            System.out.println("Thread: " + threadName + ", " + i);
            // Let the thread sleep for a while
            Thread.sleep(50);
         }
      } catch (InterruptedException e) {
         System.out.println("Thread " +  threadName + " interrupted.");
      }
      System.out.println("Thread " +  threadName + " exiting.");
   }
   
   public void start() {
      System.out.println("Starting " +  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();
   }   
}

The compilation and running results of the above program are as follows:

Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running 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 exiting.
Thread Thread-2 exiting.

Thread Method

The following table lists some important methods of the Thread class:

NummerBeschreibung der Methode
                1public void start()
Cause this thread to start executing;Java The virtual machine calls the run method of this thread.
                2public void run()
If this thread is constructed using an independent Runnable running object, call the run method of this Runnable object; otherwise, this method does nothing and returns.
                3public final void setName(String name)
Change the thread name to match the parameter name.
                4public final void setPriority(int priority)
 Change the priority of the thread.
                5public final void setDaemon(boolean on)
Set this thread as a daemon thread or a user thread.
                6public final void join(long millisec)
Warten Sie bis der Thread beendet wird, längstens millis Millisekunden.
                7public void interrupt()
Unterbrechen Sie den Thread.
                8public final boolean isAlive()
Testen Sie, ob der Thread aktiv ist.

Testen Sie, ob der Thread aktiv ist. Die folgenden Methoden werden vom Thread-Objekt aufgerufen. Die folgenden Methoden sind statische Methoden der Klasse Thread.

NummerBeschreibung der Methode
                1public static void yield()
Pausiert das aktuelle ausführende Thread-Objekt und führt andere Threads aus.
                2public static void sleep(long millisec)
Lassen Sie den aktuellen ausführenden Thread für die angegebene Millisekundenanzahl in die Warteposition versetzen (Ausführung pausieren), dieser Vorgang wird durch die Genauigkeit und Genauigkeit des Systemtimers und des Schedulers beeinflusst.
                3public static boolean holdsLock(Object x)
Gibt true zurück, wenn der aktuelle Thread den Monitorlock auf das angegebene Objekt hält.
                4public static Thread currentThread()
Gibt einen Verweis auf das aktuelle ausführende Thread-Objekt zurück.
                5public static void dumpStack()
Die aktuelle Stackschnur des aktuellen Threads wird auf die Standardfehlerausgabe gedruckt.

Online-Beispiel

Das folgende ThreadClassDemo-Programm zeigt einige Methoden der Klasse Thread:

// Dateiname: DisplayMessage.java
// Durch Implementierung des Interfaces Runnable wird ein Thread erstellt
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-Dateicode:

// Dateiname: GuessANumber.java
// Durch Vererbung der Klasse Thread wird ein Thread erstellt
 
public class GuessANumber extends Thread {
   private int number;
   public GuessANumber(int number) {
      this.number = number;
   }
   
   public void run() {
      int counter = 0;
      int guess = 0;
      do {
         guess = (int) (Math.random() * 100 + 1);
         System.out.println(this.getName() + "guesses" + guess);
         counter++;
      }; while(guess != number);
      System.out.println("** Richtig!" + this.getName() + "in" + counter + "guesses.**);
   }
}

ThreadClassDemo.java Dateicode:

// Dateiename: ThreadClassDemo.java
public class ThreadClassDemo {
 
   public static void main(String[] args) {
      Runnable hello = new DisplayMessage("Hello");
      Thread thread1 = new Thread(hello);
      thread1.setDaemon(true);
      thread1.setName("hello");
      System.out.println("Thread zur Begrüßung wird gestartet...");
      thread1.start();
      
      Runnable bye = new DisplayMessage("Goodbye");
      Thread thread2 = new Thread(bye);
      thread2.setPriority(Thread.MIN_PRIORITY);
      thread2.setDaemon(true);
      System.out.println("Thread zur Verabschiedung wird gestartet...");
      thread2.start();
 
      System.out.println("Thread wird gestartet...");3...);
      Thread thread3 = new GuessANumber(27);
      thread3.start();
      try {
         thread3.join();
      catch(InterruptedException e) {
         System.out.println("Thread unterbrochen.");
      }
      System.out.println("Thread wird gestartet...");4...);
      Thread thread4 = new GuessANumber(75);
      
      thread4.start();
      System.out.println("main() endet...");
   }
}

Die Ergebnisse des Laufens sind wie folgt, die Ergebnisse sind bei jedem Lauf unterschiedlich.

Erstellung des hello-Threads beginnt...
Erstellung des goodbye-Threads beginnt...
Hallo
Hallo
Hallo
Hallo
Hallo
Hallo
Auf Wiedersehen
Auf Wiedersehen
Auf Wiedersehen
Auf Wiedersehen
Auf Wiedersehen
.......

Erstellen von Threads durch Callable und Future

  • 1. Erstellen eines Implementierungsklassen für das Callable-Interface und Implementieren der Methode call(), die als Thread-Ausführungskörper dient und einen Rückgabewert hat.

  • 2. Beispiel für die Erstellung eines Callable-Implementierungsklassen, bei dem das Callable-Objekt mit einem FutureTask-Objekt verpackt wird, das den Rückgabewert der Methode call() des Callable-Objekts enthält.

  • 3. Erstellen und Starten eines neuen Threads, indem das FutureTask-Objekt als Ziel des Thread-Objekts verwendet wird.

  • 4. Aufruf der Methode get() des FutureTask-Objekts, um den Rückgabewert nach Abschluss der Ausführung des Unterthreads zu erhalten.

public class CallableThreadTest implements Callable<Integer> {
    public static void main(String[] args)  
    {  
        CallableThreadTest ctt = new CallableThreadTest();  
        FutureTask<Integer> ft = new FutureTask<>(ctt);  
        for(int i = 0; i < 100;i++)  
        {  
            System.out.println(Thread.currentThread().getName())+" "的循环变量i的值+i);  
            if(i==20)  
            {  
                new Thread(ft, "有返回值的线程").start();  
            }  
        }  
        try  
        {  
            System.out.println("子线程的返回值:")+ft.get());  
        } catch (InterruptedException e)  
        {  
            e.printStackTrace();  
        } catch (ExecutionException e)  
        {  
            e.printStackTrace();  
        }  
  
    }
    @Override  
    public Integer call() throws Exception  
    {  
        int i = 0;  
        for(;i<100;i++)  
        {  
            System.out.println(Thread.currentThread().getName())+" "+i);  
        }  
        return i;  
    }  
}

Vergleich der drei Methoden zur Erstellung von Threads

  • 1. Wenn Sie Multithreading durch die Implementierung von Runnable, Callable Schnittstellen erstellen, ist die Thread-Klasse nur die Runnable oder Callable Schnittstelle implementiert und kann andere Klassen vererben.

  • 2. Wenn Sie Multithreading durch Vererbung der Thread-Klasse erstellen, ist es einfach, und wenn Sie den aktuellen Thread benötigen, müssen Sie nicht Thread.currentThread() verwenden, sondern können einfach this verwenden, um den aktuellen Thread zu erhalten.

Einige Hauptkonzepte von Threads

Bei der Multithreading-Programmierung müssen Sie sich mit folgenden Konzepten vertraut machen:

  • Thread-Synchronisation

  • Kommunikation zwischen Threads

  • Thread-Deadlock

  • Thread-Kontrolle: Sperren, Stoppen und Wiederherstellen

Verwendung von Multithreading

Der Schlüssel zur effektiven Nutzung von Multithreading ist das Verständnis, dass das Programm parallel und nicht sequentiell ausgeführt wird. Zum Beispiel: Wenn zwei Unter-Systeme parallel ausgeführt werden müssen, muss auf Multithreading-Programmierung zurückgegriffen werden.

Durch die Verwendung von Multithreading kann man sehr effiziente Programme schreiben. Beachten Sie jedoch, dass die Effizienz der Programmausführung tatsächlich verringert wird, wenn Sie zu viele Threads erstellen, anstatt zu verbessern.

Denken Sie daran, dass der Aufwand für den Kontexttausch ebenfalls wichtig ist. Wenn Sie zu viele Threads erstellen, verbringt der CPU mehr Zeit mit dem Kontexttausch als mit der Ausführung des Programms!