這篇文章將為大家詳細(xì)講解有關(guān)Java中啟動(dòng)線程的正確和錯(cuò)誤方式是什么,小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。
創(chuàng)新互聯(lián)公司為您提適合企業(yè)的網(wǎng)站設(shè)計(jì)?讓您的網(wǎng)站在搜索引擎具有高度排名,讓您的網(wǎng)站具備超強(qiáng)的網(wǎng)絡(luò)競(jìng)爭(zhēng)力!結(jié)合企業(yè)自身,進(jìn)行網(wǎng)站設(shè)計(jì)及把握,最后結(jié)合企業(yè)文化和具體宗旨等,才能創(chuàng)作出一份性化解決方案。從網(wǎng)站策劃到做網(wǎng)站、網(wǎng)站設(shè)計(jì), 我們的網(wǎng)頁(yè)設(shè)計(jì)師為您提供的解決方案。
代碼演示:
/** * <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
方法可以啟動(dòng)一個(gè)新線程。
start
方法之后, 當(dāng)前線程(通常是主線程)會(huì)請(qǐng)求 JVM 虛擬機(jī)如果有空閑的話來(lái)啟動(dòng)一下這邊的這個(gè)新線程。start
方法,也不一定能夠立刻的啟動(dòng)線程。srtart
方法調(diào)用之后,并不意味這個(gè)方法已經(jīng)開(kāi)始運(yùn)行了。它可能稍后才會(huì)運(yùn)行,也很有可能很長(zhǎng)時(shí)間都不會(huì)運(yùn)行,比如說(shuō)遇到了饑餓的情況。start
方法,而線程 2 后調(diào)用了 start
方法,卻發(fā)現(xiàn)線程 2 先執(zhí)行線程 1 后執(zhí)行的情況。start
方法的順序并不能決定真正線程執(zhí)行的順序。start
方法會(huì)牽扯到兩個(gè)線程。start
方法,第二個(gè)才是新的線程。start
就已經(jīng)是子線程去執(zhí)行了,這個(gè)語(yǔ)句其實(shí)是主線程或者說(shuō)是父線程來(lái)執(zhí)行的,被執(zhí)行之后才去創(chuàng)建新線程。start
方法創(chuàng)建新線程的準(zhǔn)備工作
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)看看源碼能了解的更透徹。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ù)制代碼
第一步:啟動(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ù)制代碼
@Overridepublic void run() { // 傳入了 target 對(duì)象(即 Runnable 接口的實(shí)現(xiàn)), 執(zhí)行傳入的 target 對(duì)象的 run 方法 if (target != null) { target.run(); } }復(fù)制代碼
第一種: 重寫(xiě)了 Thread
類的 run
方法,Thread
的 run
方法會(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í)行線程就是我們的主線程。run
方法,而是要調(diào)用 start
方法,其中可以間接的調(diào)用 run
方法。關(guān)于Java中啟動(dòng)線程的正確和錯(cuò)誤方式是什么就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到。
名稱欄目:Java中啟動(dòng)線程的正確和錯(cuò)誤方式是什么
標(biāo)題網(wǎng)址:http://www.rwnh.cn/article20/gdgcco.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供定制開(kāi)發(fā)、網(wǎng)站建設(shè)、App開(kāi)發(fā)、網(wǎng)站改版、手機(jī)網(wǎng)站建設(shè)、標(biāo)簽優(yōu)化
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(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)