Java 教程

Java 控制語句

面向物件程式設計

Java 內建類

Java 檔案處理

Java 錯誤與異常

Java 多執行緒

Java 同步

Java 網路

Java 集合

Java 介面

Java 資料結構

Java 集合演算法

高階 Java

Java 雜項

Java API 和框架

Java 類參考

Java 有用資源

Java - 多執行緒



Java 是一種多執行緒程式語言,這意味著我們可以使用 Java 開發多執行緒程式。多執行緒程式包含兩個或多個可以併發執行的部分,並且每個部分可以同時處理不同的任務,從而充分利用可用資源,尤其是在您的計算機有多個CPU時。

根據定義,多工處理是指多個程序共享 CPU 等公共處理資源。多執行緒將多工處理的概念擴充套件到應用程式中,在應用程式中,您可以將單個應用程式內的特定操作細分為單獨的執行緒。每個執行緒都可以並行執行。作業系統不僅在不同的應用程式之間分配處理時間,而且在應用程式內的每個執行緒之間分配處理時間。

Java 多執行緒

多執行緒使您能夠以一種方式編寫程式碼,在該程式碼中,多個活動可以在同一程式中併發進行。為了實現多執行緒(或編寫多執行緒程式碼),您需要java.lang.Thread 類

Java 多執行緒中執行緒的生命週期

執行緒在其生命週期中會經歷各個階段。例如,執行緒誕生、啟動、執行,然後死亡。下圖顯示了執行緒的完整生命週期。

Java Thread Life Cycle

以下是生命週期的階段:

  • 新建 - 新執行緒從新建狀態開始其生命週期。它保持在此狀態,直到程式啟動執行緒。它也稱為新生執行緒

  • 可執行 - 新生執行緒啟動後,執行緒變為可執行狀態。處於此狀態的執行緒被認為正在執行其任務。

  • 等待 - 有時,執行緒在等待另一個執行緒執行任務時會過渡到等待狀態。執行緒僅在另一個執行緒發出訊號讓等待執行緒繼續執行時才返回到可執行狀態。

  • 計時等待 - 可執行執行緒可以在指定的時間間隔內進入計時等待狀態。處於此狀態的執行緒在該時間間隔到期或其等待的事件發生時返回到可執行狀態。

  • 終止(死亡) - 可執行執行緒在完成其任務或以其他方式終止時進入終止狀態。

執行緒優先順序

每個 Java 執行緒都有一個優先順序,它可以幫助作業系統確定執行緒的排程順序。

Java 執行緒優先順序範圍在 MIN_PRIORITY(常量 1)和 MAX_PRIORITY(常量 10)之間。預設情況下,每個執行緒都分配了 NORM_PRIORITY(常量 5)的優先順序。

優先順序較高的執行緒對程式更重要,應在優先順序較低的執行緒之前分配處理器時間。但是,執行緒優先順序不能保證執行緒執行的順序,並且在很大程度上取決於平臺。

透過實現 Runnable 介面建立執行緒

如果您的類旨在作為執行緒執行,那麼您可以透過實現Runnable介面來實現。您需要遵循三個基本步驟:

步驟 1:實現 run() 方法

第一步,您需要實現Runnable介面提供的 run() 方法。此方法為執行緒提供了一個入口點,您將在其中放置完整的業務邏輯。以下是 run() 方法的簡單語法:

public void run( )

步驟 2:例項化 Thread 物件

第二步,您將使用以下建構函式例項化Thread物件:

Thread(Runnable threadObj, String threadName);

其中,threadObj是實現Runnable介面的類的例項,threadName是賦予新執行緒的名稱。

步驟 3:使用 start() 方法呼叫執行緒

建立 Thread 物件後,您可以透過呼叫start()方法啟動它,該方法會執行對 run( ) 方法的呼叫。以下是 start() 方法的簡單語法:

void start();

示例:透過實現 Runnable 介面建立執行緒

這是一個建立新執行緒並開始執行它的示例:

class RunnableDemo implements Runnable {
   private Thread t;
   private String threadName;
   
   RunnableDemo( 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[]) {
      RunnableDemo R1 = new RunnableDemo( "Thread-1");
      R1.start();
      
      RunnableDemo R2 = new RunnableDemo( "Thread-2");
      R2.start();
   }   
}

輸出

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 類建立執行緒

建立執行緒的第二種方法是建立一個擴充套件Thread類的新的類,使用以下兩個簡單的步驟。這種方法在處理使用Thread類中可用方法建立的多個執行緒時提供了更大的靈活性。

步驟 1:重寫 run() 方法

您需要重寫Thread類中可用的run( )方法。此方法為執行緒提供了一個入口點,您將在其中放置完整的業務邏輯。以下是run()方法的簡單語法:

public void run( )

步驟 2:使用 start() 方法呼叫執行緒

建立Thread物件後,您可以透過呼叫start()方法啟動它,該方法會呼叫run( )方法。以下是start()方法的簡單語法:

void start( );

示例:透過擴充套件Thread類建立執行緒

以下是前面程式重寫為擴充套件Thread的示例:

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();
   }   
}

輸出

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類中可用的一些重要方法列表。

序號 方法及描述
1

public void start()

在單獨的執行路徑中啟動執行緒,然後在此Thread物件上呼叫run()方法。

2

public void run()

如果此Thread物件是使用單獨的Runnable目標例項化的,則在此Runnable物件上呼叫run()方法。

3

public final void setName(String name)

更改Thread物件的名稱。還有一個getName()方法用於檢索名稱。

4

public final void setPriority(int priority)

設定此Thread物件的優先順序。可能的值介於1到10之間。

5

public final void setDaemon(boolean on)

值為true表示此執行緒為守護執行緒。

6

public final void join(long millisec)

當前執行緒在此第二個執行緒上呼叫此方法,導致當前執行緒阻塞,直到第二個執行緒終止或指定的毫秒數過去。

7

public void interrupt()

中斷此執行緒,使其繼續執行(如果由於任何原因而被阻塞)。

8

public final boolean isAlive()

如果執行緒處於活動狀態,則返回true,即執行緒啟動後但在執行完成之前。

之前的方法是在特定的Thread物件上呼叫的。Thread類中的以下方法是靜態的。呼叫其中一個靜態方法會在當前正在執行的執行緒上執行操作。

序號 方法及描述
1

public static void yield()

導致當前正在執行的執行緒讓出給任何其他具有相同優先順序且正在等待排程的執行緒。

2

public static void sleep(long millisec)

導致當前正在執行的執行緒至少阻塞指定毫秒數。

3

public static boolean holdsLock(Object x)

如果當前執行緒持有給定Object上的鎖,則返回true。

4

public static Thread currentThread()

返回對當前正在執行的執行緒的引用,該執行緒是呼叫此方法的執行緒。

5

public static void dumpStack()

列印當前正在執行的執行緒的堆疊跟蹤,這在除錯多執行緒應用程式時很有用。

示例

以下ThreadClassDemo程式演示了Thread類的一些方法。考慮一個實現RunnableDisplayMessage類:

// File Name : DisplayMessage.java
// Create a thread to implement Runnable

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

以下是另一個擴充套件Thread類的類:

// File Name : GuessANumber.java
// Create a thread to extentd Thread

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("** Correct!" + this.getName() + "in" + counter + "guesses.**");
   }
}

以下是主程式,它使用了上面定義的類:

// File Name : 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("Starting hello thread...");
      thread1.start();
      
      Runnable bye = new DisplayMessage("Goodbye");
      Thread thread2 = new Thread(bye);
      thread2.setPriority(Thread.MIN_PRIORITY);
      thread2.setDaemon(true);
      System.out.println("Starting goodbye thread...");
      thread2.start();

      System.out.println("Starting thread3...");
      Thread thread3 = new GuessANumber(27);
      thread3.start();
      try {
         thread3.join();
      } catch (InterruptedException e) {
         System.out.println("Thread interrupted.");
      }
      System.out.println("Starting thread4...");
      Thread thread4 = new GuessANumber(75);
      
      thread4.start();
      System.out.println("main() is ending...");
   }
}
class DisplayMessage implements Runnable {
   private String message;
   
   public DisplayMessage(String message) {
      this.message = message;
   }
   
   public void run() {
      while(true) {
         System.out.println(message);
      }
   }
}
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("** Correct!" + this.getName() + "in" + counter + "guesses.**");
   }
}

輸出

Starting hello thread...
Starting goodbye thread...
Hello
Hello
Hello
Hello
Hello
Hello
Goodbye
Goodbye
Goodbye
Goodbye
Goodbye
.......

主要的Java多執行緒概念

在Java中進行多執行緒程式設計時,您需要掌握以下概念:

廣告