最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

如何在Java 中創(chuàng)建線程

 更新時間:2025年12月18日 16:01:13   作者:Boilermaker1992  
Java中創(chuàng)建線程的唯一方式是調(diào)用Thread類的start()方法,通過繼承Thread類或?qū)崿F(xiàn)Runnable接口可以為線程提供可執(zhí)行任務(wù),實現(xiàn)Callable接口并將其包裝在FutureTask中,可以獲取異步任務(wù)的執(zhí)行結(jié)果,本文介紹在Java中創(chuàng)建線程的方法,感興趣的朋友跟隨小編一起看看吧

事實上,Java 有且僅有一種方式可以真正創(chuàng)建出線程,那就是通過調(diào)用 Thread 類中的 start() 方法。因為只有這個方法會去真正調(diào)用 JVM 本地方法,進而進行操作系統(tǒng)創(chuàng)建線程的系統(tǒng)調(diào)用,并讓 Java 線程與操作系統(tǒng)線程產(chǎn)生映射關(guān)系,最后將實現(xiàn)了 Runnable 接口的任務(wù)傳遞給線程。只要線程獲得了 CPU 時間片,就進入 run() 方法執(zhí)行具體的代碼邏輯。

? 所以,僅僅有 start 方法我們就可以創(chuàng)建一個線程了,如下面的代碼所示。只不過這個線程什么都不會做,它是一個空線程,因為我們沒有以任何方式提供給其 “可執(zhí)行任務(wù)”。

public class Demo1 {
    public static void main(String[] args) {
        Thread thread = new Thread();
        System.out.println(thread.getName()); // Thread-0
        System.out.println(thread.getState()); // NEW
        thread.start();
        System.out.println(thread.getState()); // RUNNABLE
    }
}

? 在下面介紹的所謂創(chuàng)建線程的方式,其實就是在介紹為線程提供 “可執(zhí)行任務(wù)” 的方式,這些方式最終都會調(diào)用到 Thread 類中的 start() 方法。

1. 繼承 Thread 類

? 這種方式是通過重寫 Thread 類中的 run() 方法來為線程提供可執(zhí)行任務(wù)。

class MyThread extends Thread {
    public void run() {
        System.out.println(currentThread().getName());
    }
}
public class Demo2 {
    public static void main(String[] args) {
        Thread myThread1 = new MyThread();
        Thread myThread2 = new MyThread();
        myThread1.start(); // Thread-0
        myThread2.start(); // Thread-1
    }
}

? 這種方式一般是不推薦使用的,因為它在邏輯上不能將 ”線程“ 的概念和 ”線程任務(wù)“ 的概念很好地分離開。假設(shè)現(xiàn)在我有一個數(shù)字,我想要使用兩個線程同時對這個數(shù)字進行增加,直至這個數(shù)字變?yōu)?100。如果要通過繼承 Thread 類實現(xiàn),這個數(shù)字就只能作為 Thread 子類的一個靜態(tài)屬性存在,只有這樣這個變量才能在類實例之間共享。但是,這樣做就會導(dǎo)致代碼可讀性和可維護性都很差,因為自增數(shù)字是一個任務(wù),現(xiàn)在它被耦合在線程中。因此我們大部分情況還是要使用接下來介紹的方式。

? 不過,通過繼承 Thread 類實現(xiàn)共享數(shù)字自增的代碼我也放在下面,感興趣的可以看一下,這里使用 CAS 保證線程安全,不懂的話可以先略過這塊。

class MyThread extends Thread {
    private final static AtomicInteger goodsAmount = new AtomicInteger(0);
    public void run() {
        while (true) {
            // 使用 current 作為線程內(nèi)部的臨時變量,相當于快照,無線程安全問題
            int current = goodsAmount.get();
            if (current >= 200) {
                break;
            }
            // 當且僅當 goodsAmount 的值沒有被其他線程修改過時自增,
            // 如果被修改過那它的值肯定不是剛剛記錄過的 current 了。
            if (goodsAmount.compareAndSet(current, current + 1)) {
                // 每個線程只會在成功 CAS 的時候打印一次,并且打印的是增加后的值。
                // 所以這里的日志應(yīng)該嚴格打印 200 次
                System.out.println(currentThread().getName() + ":" + (current + 1));
            }
        }
    }
}
public class Demo2 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Thread myThread1 = new MyThread();
        Thread myThread2 = new MyThread();
        Thread myThread3 = new MyThread();
        myThread1.start();
        myThread2.start();
        myThread3.start();
        myThread1.join();
        myThread2.join();
        myThread3.join();
    }
}

2. 實現(xiàn) Runnable 接口

? 我們先來觀察 Thread 類中 run() 方法的源碼。如果我們不選擇重寫它,那么可以看出這個方法主要進行了一個邏輯判斷,如果 task 為空就什么都不做,如果 task 不為空就調(diào)用 runWith 真正執(zhí)行該任務(wù)。那么 task 什么時候不為空呢,就是當我們在 Thread 的構(gòu)造器中傳入任務(wù)的時候,這才引出了下面的幾種方式。

    @Override
    public void run() {
        Runnable task = holder.task;
        if (task != null) {
            Object bindings = scopedValueBindings();
            runWith(bindings, task);
        }
    }

? 如下展示了三種通過實現(xiàn) Runnable 接口來為線程傳遞可執(zhí)行任務(wù)的方式:

class Task implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}
public class Demo2 {
    public static void main(String[] args) {
        new Thread(new Task()).start(); // Thread-2
        new Thread(new Runnable() { // 使用匿名內(nèi)部類
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        }).start(); // Thread-3
        new Thread(() -> { // 使用 lambda 表達式
                System.out.println(Thread.currentThread().getName());
        }).start(); // Thread-4
    }
}

3. 獲取異步執(zhí)行結(jié)果

? 上面的兩種方式都不能獲取異步執(zhí)行結(jié)果,因為 run() 方法返回 void,這表示我們沒有管控線程執(zhí)行任務(wù)的能力:我們無法中途停止任務(wù),也無法獲取任務(wù)的執(zhí)行狀態(tài),更無法獲取任務(wù)執(zhí)行結(jié)果。

? 在 Java 中,獲取異步任務(wù)執(zhí)行信息的功能由 Future 接口進行規(guī)范,而一個可執(zhí)行任務(wù)由 Runnable 接口進行規(guī)范。這意味著,只有同時實現(xiàn)這兩個接口的類才可以作為一個 “可獲取異步執(zhí)行結(jié)果的可執(zhí)行任務(wù)” 傳入 Thread 的構(gòu)造器。

? 這個類就是 FutureTask,它真正實現(xiàn)了上述功能,這依賴于它的兩個關(guān)鍵屬性 Callable<V> callableObject outcome。前者是我們傳入的帶返回值的異步任務(wù);后者是 FutureTask 保存的任務(wù)執(zhí)行后的返回值。FutureTask 提供了 get() 方法供我們?nèi)〕?outcome,同時還提供了取消任務(wù)、判斷任務(wù)是否執(zhí)行完、判斷任務(wù)是否被取消等獲取異步任務(wù)執(zhí)行信息的功能。

所以,現(xiàn)在的邏輯變成了:我們需要先讓自己的任務(wù)實現(xiàn) Callable 接口,這表示我們的任務(wù)是一個經(jīng) Callable 規(guī)范的、有返回值的任務(wù)。接下來,我們還要把任務(wù)包裝在 FutureTask 中,傳入 Thread 的構(gòu)造器。Thread 不管你提供的到底是什么任務(wù),只要實現(xiàn)了 Runnable 即可,因為這規(guī)范了你傳入任務(wù)一定會有一個 run() 方法。Thread 先調(diào)用自己的 run() 方法,在內(nèi)部調(diào)用到 FutureTask 的 run() 方法,F(xiàn)utureTask 的 run() 方法又會調(diào)用到我們最初實現(xiàn) Callable 接口時實現(xiàn)的 call() 方法,這里才是我們真正定義的代碼邏輯。執(zhí)行完 call() 后,F(xiàn)utureTask 將返回值保存在 outcome 屬性中,供我們?nèi)〕觥?/p>

class CallableTask implements Callable<String> {
    @Override
    public String call() {
        System.out.println(Thread.currentThread().getName());
        return "任務(wù)執(zhí)行成功!";
    }
}
public class Demo2 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask<String> futureTask = new FutureTask<>(new CallableTask());
        new Thread(futureTask).start();
        System.out.println(futureTask.get()); // 任務(wù)執(zhí)行成功!
    }
}

到此這篇關(guān)于在 Java 中創(chuàng)建線程的文章就介紹到這了,更多相關(guān)java創(chuàng)建線程內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • JavaMail入門教程之解析郵件(5)

    JavaMail入門教程之解析郵件(5)

    這篇文章主要為大家詳細介紹了JavaMail入門教程之解析郵件的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-12-12
  • java中設(shè)計模式之適配器模式

    java中設(shè)計模式之適配器模式

    這篇文章主要介紹了java中設(shè)計模式之適配器模式的相關(guān)資料,適配器模式將一個類的接口轉(zhuǎn)換成客戶期望的另一個接口。適配器讓原本不兼容的類可以合作得親密無間,需要的朋友可以參考下
    2017-09-09
  • 詳解使用@RequestBody取POST方式的json字符串

    詳解使用@RequestBody取POST方式的json字符串

    這篇文章主要介紹了詳解使用@RequestBody取POST方式的json字符串,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-12-12
  • 并發(fā)編程之Java內(nèi)存模型

    并發(fā)編程之Java內(nèi)存模型

    這篇文章主要介紹了Java并發(fā)編程之內(nèi)存模型,Java內(nèi)存模型中的順序一致性,主要介紹重排序與順序一致性內(nèi)存模型,下面文章將圍繞Java內(nèi)存模型展開內(nèi)容,需要的小伙伴可以參考一下
    2021-11-11
  • 基于Java實現(xiàn)一個自己的HTTP瀏覽器

    基于Java實現(xiàn)一個自己的HTTP瀏覽器

    這篇文章主要為大家詳細介紹了如何基于Java實現(xiàn)一個自己的HTTP瀏覽器,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下
    2024-01-01
  • Java多線程中停止線程遇到線程阻塞的處理方法詳解

    Java多線程中停止線程遇到線程阻塞的處理方法詳解

    這篇文章主要介紹了Java多線程中停止線程遇到線程阻塞的處理方法詳解,在阻塞狀態(tài)下,線程會釋放CPU資源,從而允許其他線程執(zhí)行,線程阻塞是實現(xiàn)多線程編程中重要的概念,可以提高程序的效率和資源利用率,需要的朋友可以參考下
    2023-10-10
  • 一次OOM排查解決過程(dump文件分析)

    一次OOM排查解決過程(dump文件分析)

    在生產(chǎn)環(huán)境中內(nèi)存溢出是最常見也是最棘手的問題之一,它可能表現(xiàn)為某個進程被OOM?killer終止、應(yīng)用崩潰、服務(wù)不可用,這篇文章主要介紹了一次OOM排查解決的相關(guān)資料,需要的朋友可以參考下
    2026-04-04
  • Spring框架基于注解的AOP之各種通知的使用與環(huán)繞通知實現(xiàn)詳解

    Spring框架基于注解的AOP之各種通知的使用與環(huán)繞通知實現(xiàn)詳解

    這篇文章主要介紹了Spring框架基于注解的AOP之各種通知的使用及其環(huán)繞通知,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習吧
    2022-11-11
  • MyBatisPlus中@TableField注解的基本使用

    MyBatisPlus中@TableField注解的基本使用

    這篇文章主要介紹了MyBatisPlus中@TableField注解的基本使用,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • Java之ThreadLocal使用常見和方式案例講解

    Java之ThreadLocal使用常見和方式案例講解

    這篇文章主要介紹了Java之ThreadLocal使用常見和方式案例講解,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下
    2021-08-08

最新評論

鹤峰县| 广宁县| 廉江市| 柘城县| 溆浦县| 田东县| 阿图什市| 二连浩特市| 任丘市| 望都县| 沽源县| 延边| 曲靖市| 安多县| 华池县| 巫山县| 松溪县| 辽源市| 鄂伦春自治旗| 台州市| 祁门县| 封开县| 深泽县| 理塘县| 芦溪县| 资兴市| 凤城市| 赤水市| 彰武县| 富顺县| 姜堰市| 红桥区| 龙门县| 和政县| 垣曲县| 长沙县| 兰坪| 西华县| 专栏| 莒南县| 延边|