Java執行緒中的start方法和run方法怎麼使用
start方法和run方法
$start()$方法用來啟動一個線程,這時此執行緒處於就緒 (可運行)狀態,並沒有運行,一旦得到$cpu$時間片,就開始執行$run()$方法。而直接呼叫$run()$方法,只是呼叫了一個類別裡的方法,其本質上還是在當前執行緒中執行的,因此只有使用$start()$方法來呼叫$run()$方法才能實現真正的多線程。
範例程式碼
@Slf4j(topic = "c.Test4") public class Test4 { public static void main(String[] args) { Thread t1 = new Thread("t1"){ @Override public void run() { log.debug("running"); } }; t1.run(); } }
上述程式碼是直接呼叫的$run()$方法。可以看到列印訊息裡,是$main$執行緒執行了這個方法。
@Slf4j(topic = "c.Test4") public class Test4 { public static void main(String[] args) { Thread t1 = new Thread("t1"){ @Override public void run() { log.debug("running"); } }; t1.start(); } }
而如果使用$start()$方法啟動,才是真正的由$t1$執行緒執行的$run$方法。
注意
要注意的是,當$Thread$物件呼叫了$start()$方法後,就會進入就緒狀態,處於就緒狀態時無法再呼叫$start() $方法,否則就會拋出$IllegalThreadStateException$異常,如下程式碼所示
@Slf4j(topic = "c.Test4") public class Test4 { public static void main(String[] args) { Thread t1 = new Thread("t1"){ @Override public void run() { log.debug("running"); } }; t1.start(); t1.start(); } }
異常訊息:
- 呼叫$sleep()$方法會讓目前執行緒從$Running$狀態變成$Time Waiting$狀態(阻塞)
- 其它線程可以使用$interrupt$方法打斷正在睡眠的線程,此時$sleep$方法會拋出InterruptedException ##睡眠結束後的執行緒未必會立刻得到執行
- 建議用$TimeUnit$的$sleep$取代$Thread$的$sleep$來獲得更好的可讀性範例程式碼
@Slf4j(topic = "c.Test5") public class Test5 { public static void main(String[] args) { Thread t1 = new Thread("t1"){ @Override public void run() { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } }; t1.start(); log.debug("t1 state {}", t1.getState()); //让主线程休眠500ms try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } log.debug("t1 state {}", t1.getState()); } } //17:13:21.729 [main] DEBUG c.Test5 - t1 state RUNNABLE //17:13:22.245 [main] DEBUG c.Test5 - t1 state TIMED_WAITING
登入後複製上述程式碼中,先啟動$t1$線程,此時列印執行緒的狀態應該是處於$RUNNABLE$狀態,而讓主執行緒休眠是防止主執行緒先執行列印,但還未進入到$sleep()$狀態。當執行到$run()$裡邊的$sleep$方法時,執行緒進入$TIMED WAITING$狀態
@Slf4j(topic = "c.Test6") public class Thread6 { public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread("t1") { @Override public void run() { try { log.debug("enter sleep"); Thread.sleep(2000); } catch (InterruptedException e) { log.debug("wake up"); e.printStackTrace(); } } }; t1.start(); Thread.sleep(1000); log.debug("interrupt t1"); //被唤醒 t1.interrupt(); } }
上述程式碼中,當$start$方法啟動後,$t1$線程進入睡眠狀態,列印提示訊息,睡眠時間為$2s$,在$main$線程中睡眠$1s$後打斷$t1$執行緒的睡眠,提示打斷訊息,並且呼叫$interrupt()$方法,此時執行緒被打斷,拋出異常。
$TimeUnit$類別中新增了以什麼單位去睡眠,可讀性更好,但是本質上沒區別,只是進行了單位換算
TimeUnit.SECONDS.sleep(1);//该语句作用是睡眠一秒
yield
呼叫$yield$會讓當前行程從$Running$進入到$Runnable$就緒狀態,然後調度執行其他執行緒具體的實作依賴作業系統的任務調度器,(即當任務調度器中沒有其他任務時,即使讓出$cpu$,也會繼續執行該線程)$sleep$執行後是進入阻塞狀態,此時睡眠時間不結束,就不會分配$cpu$給該線程,但是$yield$是進入就緒狀態,即如果沒有其他線程需要執行,那麼也會給該線程分配時間片,這是$sleep$和$yield$的最大區別線程優先權
線程優先級
會提示調度器優先調度該線程,但它只是一個提示,調度器可以忽略他
如果$cpu$比較忙,那麼優先順序高的會獲得更多的時間片,可$cpu$空閒時,優先權幾乎沒有
sleep的應用-防止cpu佔用100%
#在沒有利用$cpu$來計算時,不要讓$while(true )$空轉浪費$cpu$,這時可以使用$yield$或$sleep$來讓$cpu$的使用權交給其他程式
while (true) { try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } }
可以使用$wait$或條件變數達到類似的效果
不同的是後兩者都需要加鎖,並且需要對應的喚醒操作,一般適用於要進行同步的場景$sleep$適用於無需鎖定同步的場景
join方法
@Slf4j(topic = "c.Test6")
public class Test6 {
static int r = 0;
public static void main(String[] args) {
test();
}
private static void test() {
log.debug("开始");
Thread t = new Thread("t1") {
@Override
public void run() {
log.debug("开始");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("结束");
r = 10;
}
};
t.start();
log.debug("r的值是{}", r);
log.debug("结束");
}
}
#因為主執行緒和$t1$執行緒是並行的,$t1$執行緒需要$1s$後才能計算出$r$的值,而主執行緒一開始就要列印$r$的值,因此列印的值為0
##解決方法:
在$t.start();$後邊加上$t.join();$即可。 $join$的作用是等待某個執行緒運行結束。 以呼叫方的角度來說,需要等待結果回傳才能繼續執行就是同步,不需要等待回傳結果就能繼續執行的就是非同步。
因此$join$方法實際上是讓其同步執行
interrupt方法
打断$sleep, wait, join$的线程,即打断阻塞状态的线程
打断$sleep$的线程,会清空打断状态
@Slf4j(topic = "c.Test7") public class Test7 { public static void main(String[] args) throws InterruptedException { Thread t = new Thread("t1"){ @Override public void run() { log.debug("sleep..."); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } } }; t.start(); Thread.sleep(1000); log.debug("interrupt"); t.interrupt(); log.debug("打断标记: {}", t.isInterrupted()); } }
打断正常运行的线程,不会清空打断状态
因此我们可以在线程中判断打断标记,来决定是否被打断,以及执行被打断之前的收尾工作。
@Slf4j(topic = "c.Test8") public class Test8 { public static void main(String[] args) throws InterruptedException { Thread t = new Thread("t1"){ @Override public void run() { while (true) { if (Thread.currentThread().isInterrupted()) { log.debug("线程被打断了"); break; } } } }; t.start(); Thread.sleep(1000); log.debug("interrupt"); t.interrupt(); } }
守护线程
默认情况下,$java$需要等待所有线程都运行结束,才会结束。有一种特殊的线程叫做守护线程,只要其他非守护线程运行结束了,即使守护线程的代码没有执行完毕,也会强制结束。
@Slf4j(topic = "c.Test10") public class Test10 { public static void main(String[] args) throws InterruptedException { Thread t = new Thread("t1") { @Override public void run() { while (true) { } } }; //设置线程为守护线程 t.setDaemon(true); t.start(); Thread.sleep(1000); log.debug("主线程结束"); } }
如果不把$t$设置为守护线程,则因为线程内部的死循环,导致程序不会结束运行。
以上是Java執行緒中的start方法和run方法怎麼使用的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

熱門話題

Java 8引入了Stream API,提供了一種強大且表達力豐富的處理數據集合的方式。然而,使用Stream時,一個常見問題是:如何從forEach操作中中斷或返回? 傳統循環允許提前中斷或返回,但Stream的forEach方法並不直接支持這種方式。本文將解釋原因,並探討在Stream處理系統中實現提前終止的替代方法。 延伸閱讀: Java Stream API改進 理解Stream forEach forEach方法是一個終端操作,它對Stream中的每個元素執行一個操作。它的設計意圖是處

膠囊是一種三維幾何圖形,由一個圓柱體和兩端各一個半球體組成。膠囊的體積可以通過將圓柱體的體積和兩端半球體的體積相加來計算。本教程將討論如何使用不同的方法在Java中計算給定膠囊的體積。 膠囊體積公式 膠囊體積的公式如下: 膠囊體積 = 圓柱體體積 兩個半球體體積 其中, r: 半球體的半徑。 h: 圓柱體的高度(不包括半球體)。 例子 1 輸入 半徑 = 5 單位 高度 = 10 單位 輸出 體積 = 1570.8 立方單位 解釋 使用公式計算體積: 體積 = π × r2 × h (4

Spring Boot簡化了可靠,可擴展和生產就緒的Java應用的創建,從而徹底改變了Java開發。 它的“慣例慣例”方法(春季生態系統固有的慣例),最小化手動設置
