$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方法與yield方法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
@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
線程優先級
sleep的應用-防止cpu佔用100%
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$方法實際上是讓其同步執行
#有實效的等待$join(毫秒)$方法裡可以有一個參數是傳入等待的時間,如果執行緒執行時間大於等待時間,等待時間到了之後,就會停止等待。如果執行緒執行時間小於等待時間,則執行緒執行完畢之後,等待也會跟著結束。不會把設定的等待時間過完。打断$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中文網其他相關文章!