成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Java 并發編程:本質上只有一種創建線程的方法

開發
在上一篇文章中,我們學習了操作系統中線程的基本概念。那么在 Java 中,我們如何創建和使用線程呢?

上一篇文章中,我們學習了操作系統中線程的基本概念。那么在 Java 中,我們如何創建和使用線程呢?首先請思考一個問題。創建線程有多少種方法呢?大多數人會說有 2 種、3 種或 4 種。很少有人會說只有 1 種。讓我們看看他們實際指的是什么。最常見的答案是兩種創建線程的方法。讓我們先看看這兩種線程創建方法的代碼。

Thread 類和 Runnable 接口

(1) 繼承 Thread 類:第一種是繼承 Thread 類并重寫 run() 方法:

class SayHelloThread extends Thread {
    public void run() {
        System.out.println("hello world");
    }
}

public class ThreadJavaApp {
    public static void main(String[] args) {
        SayHelloThread sayHelloThread = new SayHelloThread();
        sayHelloThread.start();
    }
}

只有在主線程中創建 MyThread 的實例并調用 start() 方法,線程才會啟動。

(2) 實現 Runnable 接口:接下來看看 Runnable 接口:

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

實現 Runnable 接口的 run() 方法,在這個方法里可以定義相應的業務邏輯,不過我們還是需要通過 Thread 類來啟動線程。

class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("Hello Runnable");
    }
}

public class RunnableDemo {
    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();
        new Thread(myRunnable).start();
    }
}

從 Runnable 接口的定義中可以看出,Runnable 是一個函數式接口(JDK 1.8 及以上),這意味著我們可以使用 Java 8 的函數式編程來簡化代碼:

public class RunnableDemo {
    public static void main(String[] args) {
        // Java 8 函數式編程,可以省略 MyThread 類的定義
        new Thread(() -> {
            System.out.println("Lambda 表達式實現 Runnable");
        }).start();
    }
}

Callable、Future 和 FutureTask

一般來說,我們使用 Runnable 和 Thread 來創建一個新線程。然而,它們有一個缺點,即 run 方法沒有返回值。有時我們希望啟動一個線程來執行任務,并且在任務完成后有一個返回值。JDK 為我們提供了 Callable 接口來解決這個問題。

(1) Callable 接口:Callable 與 Runnable 類似,它也是一個只有一個抽象方法的函數式接口。不同之處在于 Callable 提供的方法有返回值并支持泛型。

@FunctionalInterface
public interface Callable<V> {
    V call() throws Exception;
}

那么 Callable 通常如何使用呢?它是否與 Runnable 接口一樣,傳入 Thread 類呢?讓我們查看 JDK8 的 Java API,發現沒有使用 Callable 作為參數的構造方法。

(2) Future 接口和 FutureTask 類:實際上它提供了 FutureTask 類來完成有返回值的異步計算。FutureTask 實現了 RunnableFuture 接口,而 RunnableFuture 接口同時繼承了 Runnable 接口和 Future 接口,因此可以傳入 Thread(Runable target)。

public interface RunnableFuture<V> extends Runnable, Future<V> {
  /**
     * Sets this Future to the result of its computation,
     * unless it has been cancelled.
     */
    void run();
}

Future 接口只有幾個簡單的方法:

public abstract interface Future<V> {
    public abstract boolean cancel(boolean paramBoolean);
    public abstract boolean isCancelled();
    public abstract boolean isDone();
    public abstract V get() throws InterruptedException, ExecutionException;
    public abstract V get(long paramLong, TimeUnit paramTimeUnit)
            throws InterruptedException, ExecutionException, TimeoutException;
}

每個方法的功能如下:

  • get():等待計算完成并返回結果。
  • get(long paramLong, TimeUnit paramTimeUnit):等待設定的時間。如果在設定時間內計算完成,則返回結果,否則拋出 TimeoutException。
  • isDone:如果任務完成,則返回 true。完成可能是由于正常終止、異常或取消。在所有這些情況下,方法都將返回 true。
  • isCancelled:如果此任務在正常完成之前被取消,則返回 true。
  • cancel:嘗試取消線程的執行。請注意,這是嘗試取消,不一定能成功取消。因為任務可能已經完成、被取消或由于其他一些因素而無法取消,所以取消可能會失敗。布爾類型的返回值表示取消是否成功。參數 paramBoolean 表示是否通過中斷線程來取消線程執行。

有時使用 Callable 而不是 Runnable 是為了能有取消任務的能力。如果使用 Future 只是為了可以取消任務但不提返回結果可以聲明 Future<? >的類型,并將底層任務的結果返回為 null。

你可能會問,為什么要有 FutureTask 類呢?前面說過 Future 只是一個接口,其方法 cancel、get、isDone 等如果自己實現會非常復雜。因此 JDK 為我們提供了 FutureTask 類供我們直接使用。

FutureTask 需要與 Callable 結合使用來完成有返回值的異步計算,這里看一個其使用的簡單示例:

class MyCallable implements Callable<Integer> {
    /**
     * 計算 1 到 4 的總和
     * @return
     */
    @Override
    public Integer call() {
        int res = 0;
        for (int i = 0; i < 5; i++) {
            res += i;
        }
        return res;
    }
}

publicclass CallableDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 1. 生成 MyCallable 的實例
        MyCallable myCallable = new MyCallable();
        // 2. 通過 myCallable 創建 FutureTask 對象
        FutureTask<Integer> futureTask = new FutureTask<>(myCallable);
        // 3. 通過 FutureTask 創建 Thread 對象
        Thread t = new Thread(futureTask);
        // 4. 啟動線程
        t.start();
        // 5. 獲取計算結果
        Integer res = futureTask.get();
        System.out.println(res);
    }
}

輸出:

10

為什么只有一種實現線程的方法?

我相信你對這個問題基本上有了答案。無論你是實現 Runnable 接口、實現 Callable 接口還是直接繼承 Thread 類來創建線程,最終都是創建一個 Thread 實例來啟動線程,即 new Thread(),只是創建的形式不同而已!

實際上,線程不僅可以通過上述形式創建,還可以通過內置的工具類(如線程池)來創建,后續文章將單獨介紹。

實現 Runnable 接口優于繼承 Thread 類

要實現一個沒有返回值的線程類,你可以繼承 Thread 類或實現 Runnable 接口,它們之間有什么優缺點呢?

(1) Thread 類的優點:

  • 簡單直觀:由于繼承關系,代碼結構相對簡單易懂。
  • 線程控制:可以直接使用 Thread 類的方法來控制線程的狀態,如啟動、暫停、停止等。

(2) Thread 類的缺點:

  • 單繼承限制:由于 Java 不支持多重繼承,使用 Thread 類限制了類的擴展。
  • 代碼耦合:線程類和線程執行邏輯緊密耦合,不利于代碼復用和維護。

(3) Runnable 接口的優點:

  • 更好的代碼復用:由于它是一個接口,可以將線程的執行邏輯與其他類分離,以實現代碼復用。
  • 靈活性:可以同時實現多個接口,避免單繼承的限制。
  • 更好的可擴展性:接口使得在不影響現有代碼的情況下擴展線程功能變得容易。即面向接口編程的原則。

(4) Runnable 接口的缺點:

  • 代碼稍微復雜一些:需要創建一個實現 Runnable 接口的類并實現 run() 方法,然后由 Thread 類驅動。
  • 沒有線程控制方法:不能直接使用 Thread 類的線程控制方法,需要通過 Thread 對象調用它們。

所以,綜合考慮,通常建議使用 Runnable 接口的實現來創建線程,以獲得更好的代碼可復用性和可擴展性。

Thread 的 start() 方法

在程序中調用 start() 方法后,虛擬機首先為我們創建一個線程,然后等待直到這個線程獲得時間片,才會調用 run() 方法執行具體邏輯。

請注意,start() 方法不能多次調用。第一次調用 start() 方法后,再次調用會拋出 IllegalThreadStateException 異常。

你可以簡單看一下 start() 方法的源代碼。實際上,實際工作是由 start0() 完成的,它是一個本地方法,我添加了一些注釋,以便你更容易理解。

public synchronized void start() {
    /**
     * 零狀態值對應于狀態 NEW。
     */
    if (threadStatus!= 0)
        thrownew IllegalThreadStateException();
    group.add(this); // 將其所屬的線程組加上該線程
    boolean started = false;
    try {
        start0(); // 本地方法調用實際創建線程的底層方法。
        started = true;
    } finally {
        try {
            if (!started) {
                group.threadstartFailed(this);
            }
        } catch (Throwable ignore) {
            /* 什么也不做。如果 start0 拋出了 Throwable,那么
             * 它將在調用棧中向上傳遞 */
        }
    }
}

ThreadGroup 的概念將在后續文章中介紹。你可以在這里忽略它。

Thread 類的幾個常用方法

這里我們簡要提及 Thread 類的幾個常用方法,先熟悉一下。后續文章將根據具體使用場景詳細介紹:

  • currentThread():靜態方法,返回當前正在執行的線程對象的引用;
  • sleep():靜態方法,使當前線程睡眠指定的時間;
  • yield():表示當前線程愿意放棄對當前處理器的占用。請注意,即使當前線程調用了 yield() 方法,它仍然有可能繼續運行;
  • join():使當前線程等待另一個線程完成執行后再繼續,內部調用是通過 Object 類的 wait 方法實現的;

好了,這次就到這里,下次再見!

責任編輯:趙寧寧 來源: 程序猿技術充電站
相關推薦

2012-08-13 10:26:53

云計算云服務

2022-06-06 15:44:24

大數據數據分析思維模式

2022-11-22 11:18:38

Java虛擬線程

2025-02-14 10:25:53

2020-12-14 06:43:02

并發編程JDK

2024-04-01 08:38:57

Spring@AspectAOP

2023-10-24 09:03:05

C++編程

2023-12-04 08:21:18

虛擬線程Tomcat

2010-12-06 16:57:13

FreeBSDLinux

2025-02-10 08:43:31

Java異步編程

2011-02-23 09:35:25

Eclipse遠程調試

2023-07-18 18:10:04

2015-10-14 17:54:01

容器虛擬機云服務

2018-12-14 14:30:12

安全檢測布式系測試

2011-12-29 13:31:15

Java

2025-02-17 00:00:25

Java并發編程

2025-02-19 00:05:18

Java并發編程

2011-07-04 17:53:48

快速測試

2015-03-13 11:23:21

編程編程超能力編程能力

2012-07-30 09:58:53

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 97精品一区二区 | 中文字幕亚洲一区 | 蜜桃av鲁一鲁一鲁一鲁 | 中文一区二区 | 国产综合久久 | 成人免费网站www网站高清 | 亚洲第一区国产精品 | 超碰在线97国产 | 亚洲一区二区三区视频在线 | 国产剧情一区二区三区 | 一二三四在线视频观看社区 | 精品久久99 | 欧美一区二区三区四区视频 | 九九热视频这里只有精品 | 精久久久| 久久99深爱久久99精品 | 国产精品一区二区av | 一区二区伦理电影 | 自拍偷拍中文字幕 | 请别相信他免费喜剧电影在线观看 | 欧美一级三级在线观看 | 亚洲欧美日韩在线不卡 | 成人亚洲性情网站www在线观看 | 免费久久99精品国产婷婷六月 | 久久出精品 | 亚洲欧美综合精品久久成人 | 在线观看精品视频网站 | 日韩不卡视频在线 | 久久国产福利 | 日韩福利| 日韩美av | 日本 欧美 国产 | 国产精品一区二区精品 | 久久另类 | 草草视频在线观看 | 国产亚洲一区二区三区在线观看 | 亚洲一二三区在线观看 | 午夜看片| 精品视频久久久久久 | 免费观看一级毛片视频 | 亚洲毛片在线 |