執行緒的基本使用

李松燃發表於2024-07-04

執行緒

1.什麼是執行緒

執行緒(Thread)是電腦科學中的基本概念,用於描述一個程式內部的執行路徑。一個執行緒可以被看作是一個程式內部的獨立執行流,能夠單獨執行程式碼,並與其他執行緒共享同一程序的資源。以下是關於執行緒的一些詳細資訊:

  1. 執行緒的特點
    • 輕量級:執行緒是比程序更小的執行單位。一個程序中可以包含多個執行緒,每個執行緒相對獨立而且佔用的資源較少。
    • 併發執行:多個執行緒可以併發執行,各自獨立地執行自己的任務,可以實現多工處理。
    • 共享記憶體:同一程序內的執行緒共享該程序的記憶體資源,因此可以直接訪問共享變數,但也因此需要考慮執行緒安全性問題。
  2. 執行緒的建立
    • 在Java中,可以透過繼承Thread類或實現Runnable介面來建立執行緒。
    • 繼承Thread類需要重寫run()方法,然後建立Thread的例項並呼叫start()方法來啟動執行緒。
    • 實現Runnable介面需要實現run()方法,然後建立Thread的例項並將實現了Runnable介面的物件作為引數傳遞給Thread的建構函式來啟動執行緒。
  3. 執行緒的生命週期
    • 執行緒在執行過程中會經歷不同的狀態,如新建、就緒、執行、阻塞和終止等狀態。
    • 執行緒的生命週期可以透過Thread類的方法來管理和控制,比如start()方法用於啟動執行緒,sleep()和wait()方法用於使執行緒休眠或等待,join()方法用於等待一個執行緒執行完成。
  4. 執行緒排程
    • 執行緒排程是作業系統或虛擬機器對多個執行緒之間的執行順序進行管理和排程的過程。
    • 執行緒排程策略包括搶佔式排程和協作式排程,在不同的作業系統和程式設計環境中可能有不同的排程策略。
  5. 執行緒同步與執行緒安全
    • 多個執行緒訪問共享資料時會引發競爭條件和資料不一致的問題,因此需要透過同步機制來確保多執行緒安全訪問共享資源。
    • Java提供了synchronized關鍵字、Lock物件、volatile關鍵字等機制來實現執行緒同步,以避免多執行緒併發訪問導致的問題。

執行緒是併發程式設計中非常重要的概念,合理使用執行緒可以充分利用多核處理器的效能優勢,提高程式的效能和響應速度。然而,需要注意執行緒間的協作、同步和安全性問題,以避免因為多執行緒訪問共享資源而導致的意外結果。

2.建立執行緒的方式

在Java中,有兩種主要的方式來建立執行緒:

1.透過繼承Thread類:

  • 建立一個繼承自Thread類的子類,重寫子類的run()方法來定義執行緒要執行的任務。
  • 例項化子類的物件,並呼叫start()方法來啟動執行緒的執行。
public class MyThread extends Thread {
    public void run() {
        // 定義執行緒要執行的任務
        System.out.println("Thread is running");
    }
}

// 啟動執行緒
public static void main(String[] args) {
    MyThread thread = new MyThread();
    thread.start();
}

2.透過實現Runnable介面:

  • 建立一個實現了Runnable介面的類,實現介面中的run()方法來定義執行緒要執行的任務。
  • 建立Thread物件,將實現了Runnable介面的類的例項作為引數傳遞給Thread的建構函式,並呼叫start()方法來啟動執行緒的執行。
public class MyRunnable implements Runnable {
    public void run() {
        // 定義執行緒要執行的任務
        System.out.println("Runnable is running");
    }
}

// 啟動執行緒
public static void main(String[] args) {
    MyRunnable myRunnable = new MyRunnable();
    Thread thread = new Thread(myRunnable);
    thread.start();
}

這兩種方式都可以用來建立執行緒,但一般推薦使用實現Runnable介面的方式,因為Java不支援多重繼承,而實現介面可以更靈活地擴充套件其他類。另外,透過實現Runnable介面還能更好地描述任務和執行緒之間的關係,使程式碼更清晰和易於維護。

在Java中,除了透過繼承Thread類或實現Runnable介面來建立執行緒外,還可以使用Callable介面來建立執行緒。Callable介面是一個泛型介面,可以返回執行緒執行結果,並且可以丟擲異常。與Runnable介面不同的是,Callable介面的call()方法可以有返回值。

下面是使用Callable介面建立執行緒的步驟:

  1. 建立一個實現Callable介面的類,並實現call()方法來定義執行緒要執行的任務。
import java.util.concurrent.Callable;

public class MyCallable implements Callable<String> {
    public String call() throws Exception {
        // 定義執行緒要執行的任務
        return "Callable is running";
    }
}

​ 2.使用Executor框架來啟動Callable任務。Executor框架是Java併發程式設計中用來管理執行緒的工具,可以在程式中方便地提交和執行執行緒任務。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class Main {
    public static void main(String[] args) {
        MyCallable myCallable = new MyCallable();

        // 建立執行緒池
        ExecutorService executor = Executors.newFixedThreadPool(1);

        // 提交Callable任務並獲取Future物件
        Future<String> future = executor.submit(myCallable);
        
        try {
            // 獲取執行緒執行結果
            String result = future.get();
            System.out.println(result);
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        // 關閉執行緒池
        executor.shutdown();
    }
}

在上面的示例中,我們首先建立了一個實現Callable介面的類MyCallable,然後透過Executor框架建立了一個執行緒池並提交了Callable任務。最後透過Future物件獲取執行緒的執行結果。

使用Callable介面建立執行緒可以更方便地獲取執行緒的執行結果,並且可以更靈活地處理異常。相比於Runnable介面,Callable介面更適合一些需要返回結果的執行緒任務場景

3.Thread類中常用的方法

在Java中,Thread類提供了許多常用的方法來操作執行緒。以下是Thread類中常用的一些方法:

  1. start()
  • 透過呼叫start()方法來啟動執行緒,使其進入就緒狀態,等待CPU排程執行。
  1. run()
  • 在Thread類中,run()方法定義了執行緒的執行邏輯。
  1. sleep(long millis)
  • 讓當前執行緒休眠指定的時間(以毫秒為單位)。
  1. join()
  • 等待呼叫join()方法的執行緒執行完成後,當前執行緒再繼續執行。
  1. join(long millis)
  • 等待呼叫join()方法的執行緒執行完成,最多等待millis毫秒。
  1. interrupt()
  • 中斷執行緒,將執行緒的中斷標記設定為true。
  1. isInterrupted()
  • 判斷執行緒是否被中斷。
  1. getName()
  • 獲取執行緒的名稱。
  1. setName(String name)
  • 設定執行緒的名稱。
  1. yield()
  • 讓出CPU執行權,給其他執行緒執行機會。
  1. isAlive()
  • 判斷執行緒是否還存活。
  1. setPriority(int priority)
  • 設定執行緒的優先順序。
  1. getPriority()
  • 獲取執行緒的優先順序。
  1. wait()
  • 當前執行緒進入等待狀態,直到另一個執行緒呼叫notify()或notifyAll()方法喚醒它。
  1. notify() / notifyAll()
  • 喚醒正在等待的執行緒。

這些是Thread類中的一些常用方法,可以幫助我們操作執行緒的狀態和行為。根據具體的需求,我們可以選擇合適的方法來控制執行緒的執行。

4.Runable和Callable的區別

在Java中,Runnable和Callable介面都可以用來建立多執行緒,但它們之間有一些區別:

  1. 返回值
  • Runnable介面中的run()方法沒有返回值,而Callable介面中的call()方法可以返回一個結果。
  1. 異常處理
  • Runnable介面中的run()方法不能丟擲已檢查異常,但可以透過try-catch在方法內部處理異常;而Callable介面的call()方法可以丟擲異常,需要透過捕獲或宣告丟擲來處理異常。
  1. 返回結果
  • Callable介面可以返回一個結果,而Runnable介面無法直接返回結果,但可以透過共享變數或其他方式來獲取執行緒執行結果。
  1. Future類
  • 在使用Callable介面時,可以透過Future來獲取執行緒執行的結果,而Runnable介面沒有提供類似的機制。
  1. 適用場景
  • Callable適用於需要返回結果、可能丟擲異常的執行緒任務;而Runnable適用於簡單的無需返回結果、不會丟擲異常的執行緒任務。

總的來說,如果需要執行緒執行任務後返回一個結果或者丟擲異常,可以使用Callable介面;如果只是簡單的執行任務而不需要返回結果,可以使用Runnable介面。根據具體需求,選擇適合的介面來建立執行緒可以使程式碼更加清晰和方便處理執行緒任務的結果

相關文章