中文字幕日韩精品一区二区免费_精品一区二区三区国产精品无卡在_国精品无码专区一区二区三区_国产αv三级中文在线

細(xì)品Java中啟動(dòng)線程的正確和錯(cuò)誤方式

細(xì)品 Java 中啟動(dòng)線程的正確和錯(cuò)誤方式前文回顧詳細(xì)分析 Java 中實(shí)現(xiàn)多線程的方法有幾種?(從本質(zhì)上出發(fā))start 方法和 run 方法的比較

代碼演示:

讓客戶(hù)滿(mǎn)意是我們工作的目標(biāo),不斷超越客戶(hù)的期望值來(lái)自于我們對(duì)這個(gè)行業(yè)的熱愛(ài)。我們立志把好的技術(shù)通過(guò)有效、簡(jiǎn)單的方式提供給客戶(hù),將通過(guò)不懈努力成為客戶(hù)在信息化領(lǐng)域值得信任、有價(jià)值的長(zhǎng)期合作伙伴,公司提供的服務(wù)項(xiàng)目有:國(guó)際域名空間、雅安服務(wù)器托管、營(yíng)銷(xiāo)軟件、網(wǎng)站建設(shè)、濱江網(wǎng)站維護(hù)、網(wǎng)站推廣。
/**
 * <p>
 * start() 和 run() 的比較
 * </p>
 *
 * @author 踏雪彡尋梅
 * @version 1.0
 * @date 2020/9/20 - 16:15
 * @since JDK1.8
 */public class StartAndRunMethod {    public static void main(String[] args) {        // run 方法演示
        // 輸出: name: main
        // 說(shuō)明由主線程去執(zhí)行的, 不符合新建一個(gè)線程的本意
        Runnable runnable = () -> {
            System.out.println("name: " + Thread.currentThread().getName());
        };
        runnable.run();        // start 方法演示
        // 輸出: name: Thread-0
        // 說(shuō)明新建了一個(gè)線程, 符合本意
        new Thread(runnable).start();
    }
}復(fù)制代碼

從以上示例可以分析出以下兩點(diǎn):

直接使用 run方法不會(huì)啟動(dòng)一個(gè)新線程。(錯(cuò)誤方式)

start方法會(huì)啟動(dòng)一個(gè)新線程。(正確方式)

start 方法分析start 方法的含義以及注意事項(xiàng)

start方法可以啟動(dòng)一個(gè)新線程。

線程對(duì)象在初始化之后調(diào)用了 start方法之后, 當(dāng)前線程(通常是主線程)會(huì)請(qǐng)求 JVM 虛擬機(jī)如果有空閑的話來(lái)啟動(dòng)一下這邊的這個(gè)新線程。也就是說(shuō), 啟動(dòng)一個(gè)新線程的本質(zhì)就是請(qǐng)求 JVM 來(lái)運(yùn)行這個(gè)線程。至于這個(gè)線程何時(shí)能夠運(yùn)行,并不是簡(jiǎn)單的由我們能夠決定的,而是由線程調(diào)度器去決定的。如果它很忙,即使我們運(yùn)行了 start方法,也不一定能夠立刻的啟動(dòng)線程。所以說(shuō) srtart方法調(diào)用之后,并不意味這個(gè)方法已經(jīng)開(kāi)始運(yùn)行了。它可能稍后才會(huì)運(yùn)行,也很有可能很長(zhǎng)時(shí)間都不會(huì)運(yùn)行,比如說(shuō)遇到了饑餓的情況。這也就印證了有些情況下,線程 1 先掉用了 start方法,而線程 2 后調(diào)用了 start方法,卻發(fā)現(xiàn)線程 2 先執(zhí)行線程 1 后執(zhí)行的情況。總結(jié): 調(diào)用 start方法的順序并不能決定真正線程執(zhí)行的順序。注意事項(xiàng)start方法會(huì)牽扯到兩個(gè)線程。第一個(gè)就是主線程,因?yàn)槲覀儽仨氁幸粋€(gè)主線程或者是其他的線程(哪怕不是主線程)來(lái)執(zhí)行這個(gè) start方法,第二個(gè)才是新的線程。很多情況下會(huì)忽略掉為我們創(chuàng)建線程的這個(gè)主線程,不要誤以為調(diào)用了 start就已經(jīng)是子線程去執(zhí)行了,這個(gè)語(yǔ)句其實(shí)是主線程或者說(shuō)是父線程來(lái)執(zhí)行的,被執(zhí)行之后才去創(chuàng)建新線程。

start方法創(chuàng)建新線程的準(zhǔn)備工作

首先,它會(huì)讓自己處于就緒狀態(tài)。就緒狀態(tài)指已經(jīng)獲取到除了 CPU 以外的其他資源, 如已經(jīng)設(shè)置了上下文、棧、線程狀態(tài)以及 PC(PC 是一個(gè)寄存器,PC 指向程序運(yùn)行的位置) 等。做完這些準(zhǔn)備工作之后,就萬(wàn)事俱備只欠東風(fēng)了,東風(fēng)就是 CPU 資源。做完準(zhǔn)備工作之后,線程才能被 JVM 或操作系統(tǒng)進(jìn)一步去調(diào)度到執(zhí)行狀態(tài)等待獲取 CPU 資源,然后才會(huì)真正地進(jìn)入到運(yùn)行狀態(tài)執(zhí)行 run方法中的代碼。

需要注意: 不能重復(fù)的執(zhí)行 start 方法

代碼示例

/**
* <p>
* 演示不能重復(fù)的執(zhí)行 start 方法(兩次及以上), 否則會(huì)報(bào)錯(cuò)
* </p>
*
* @author 踏雪彡尋梅
* @version 1.0
* @date 2020/9/20 - 16:47
* @since JDK1.8
*/public class CantStartTwice {    public static void main(String[] args) {
        Runnable runnable = () -> {
            System.out.println("name: " + Thread.currentThread().getName());
        };
        Thread thread = new Thread(runnable);        // 輸出: name: Thread-0
        thread.start();        // 輸出: 拋出 java.lang.IllegalThreadStateException
        // 即非法線程狀態(tài)異常(線程狀態(tài)不符合規(guī)定)
        thread.start();
    }
}復(fù)制代碼

報(bào)錯(cuò)的原因

start一旦開(kāi)始執(zhí)行,線程狀態(tài)就從最開(kāi)始的 New 狀態(tài)進(jìn)入到后續(xù)的狀態(tài),比如說(shuō) Runnable,然后一旦線程執(zhí)行完畢,線程就會(huì)變成終止?fàn)顟B(tài),而終止?fàn)顟B(tài)永遠(yuǎn)不可能再返回回去,所以會(huì)拋出以上異常,也就是說(shuō)不能回到初始狀態(tài)了。這里描述的還不夠清晰,讓我們來(lái)看看源碼能了解的更透徹。start 方法源碼分析源碼
public synchronized void start() {    /**
     * This method is not invoked for the main method thread or "system"
     * group threads created/set up by the VM. Any new functionality added
     * to this method in the future may have to also be added to the VM.
     *
     * A zero status value corresponds to state "NEW".
     */
    // 第一步, 檢查線程狀態(tài)是否為初始狀態(tài), 這里也就是上面拋出異常的原因
    if (threadStatus != 0)        throw new IllegalThreadStateException();    /* Notify the group that this thread is about to be started
     * so that it can be added to the group's list of threads
     * and the group's unstarted count can be decremented. */
    // 第二步, 加入線程組
    group.add(this);    boolean started = false;    try {        // 第三步, 調(diào)用 start0 方法
        start0();
        started = true;
    } finally {        try {            if (!started) {
                group.threadStartFailed(this);
            }
        } catch (Throwable ignore) {            /* do nothing. If start0 threw a Throwable then
              it will be passed up the call stack */
        }
    }
}復(fù)制代碼
源碼中的流程

第一步:?jiǎn)?dòng)新線程時(shí)會(huì)首先檢查線程狀態(tài)是否為初始狀態(tài), 這也是以上拋出異常的原因。即以下代碼:

if (threadStatus != 0)    throw new IllegalThreadStateException();復(fù)制代碼

其中 threadStatus這個(gè)變量的注釋如下,也就是說(shuō) Java 的線程狀態(tài)最初始(還沒(méi)有啟動(dòng))的時(shí)候表示為 0:

/* Java thread status for tools,
 * initialized to indicate thread 'not yet started'
 */private volatile int threadStatus = 0;復(fù)制代碼

第二步:將其加入線程組。即以下代碼:

group.add(this);復(fù)制代碼

第三步:最后調(diào)用 start0()這個(gè) native 方法(native 代表它的代碼不是由 Java 實(shí)現(xiàn)的,而是由 C/C++ 實(shí)現(xiàn)的,具體實(shí)現(xiàn)可以在 JDK 里面看到,了解即可), 即以下代碼:

boolean started = false;try {    // 第三步, 調(diào)用 start0 方法
    start0();
    started = true;
} finally {    try {        if (!started) {
            group.threadStartFailed(this);
        }
    } catch (Throwable ignore) {        /* do nothing. If start0 threw a Throwable then
          it will be passed up the call stack */
    }
}復(fù)制代碼
run 方法分析run 方法源碼分析
@Overridepublic void run() {    // 傳入了 target 對(duì)象(即 Runnable 接口的實(shí)現(xiàn)), 執(zhí)行傳入的 target 對(duì)象的 run 方法
    if (target != null) {
        target.run();
    }
}復(fù)制代碼
對(duì)于 run 方法的兩種情況

第一種: 重寫(xiě)了 Thread類(lèi)的 run方法,Threadrun方法會(huì)失效, 將會(huì)執(zhí)行重寫(xiě)的 run方法。

第二種: 傳入了 target對(duì)象(即 Runnable接口的實(shí)現(xiàn)),執(zhí)行 Thread的原有 run方法然后接著執(zhí)行 target對(duì)象的 run方法。

總結(jié):

run方法就是一個(gè)普通的方法, 上文中直接去執(zhí)行 run方法也就是相當(dāng)于我們執(zhí)行自己寫(xiě)的普通方法一樣,所以它的執(zhí)行線程就是我們的主線程。所以要想真正的啟動(dòng)線程,不能直接調(diào)用 run方法,而是要調(diào)用 start方法,其中可以間接的調(diào)用 run方法。

相關(guān)學(xué)習(xí)推薦:java基礎(chǔ)

文章題目:細(xì)品Java中啟動(dòng)線程的正確和錯(cuò)誤方式
網(wǎng)頁(yè)地址:http://www.rwnh.cn/article10/cgspdo.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供App設(shè)計(jì)、標(biāo)簽優(yōu)化外貿(mào)建站、面包屑導(dǎo)航、網(wǎng)站建設(shè)、關(guān)鍵詞優(yōu)化

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

商城網(wǎng)站建設(shè)
仙游县| 东乌| 蒲江县| 玉龙| 阿城市| 东丽区| 双鸭山市| 平武县| 清新县| 小金县| 普陀区| 伊春市| 巴楚县| 溧水县| 图木舒克市| 连州市| 岑巩县| 云阳县| 增城市| 鱼台县| 彭山县| 桑植县| 吕梁市| 临澧县| 江油市| 上杭县| 元谋县| 鄂尔多斯市| 瑞昌市| 榆中县| 调兵山市| 张家港市| 泾阳县| 定远县| 定襄县| 广饶县| 德州市| 宁城县| 彭山县| 老河口市| 淮安市|