地下城釣魚(yú)網(wǎng)站怎么做包頭seo
📚博客主頁(yè):愛(ài)敲代碼的小楊.
?專(zhuān)欄:《Java SE語(yǔ)法》 | 《數(shù)據(jù)結(jié)構(gòu)與算法》 | 《C生萬(wàn)物》 |《MySQL探索之旅》 |《Web世界探險(xiǎn)家》
??感謝大家點(diǎn)贊👍🏻收藏?評(píng)論?🏻,您的三連就是我持續(xù)更新的動(dòng)力??
🙏小楊水平有限,歡迎各位大佬指點(diǎn),相互學(xué)習(xí)進(jìn)步!
文章目錄
- 0. 前言
- 1. Thread 的常見(jiàn)構(gòu)造方法
- 2. Thread 類(lèi)常見(jiàn)屬性
- 2.1 ID
- 2.2 名稱(chēng)
- 2.3 狀態(tài)
- 2.4 優(yōu)先級(jí)
- 2.5 是否后臺(tái)線程
- 2.6 是否存活
- 2.7 是否被中斷
- 3. 啟動(dòng)線程-start()
0. 前言
Thread
類(lèi)是 JVM 用來(lái)創(chuàng)建和管理線程的類(lèi),也就是說(shuō)每個(gè)線程都有唯一一個(gè)Thread
對(duì)象與之關(guān)聯(lián)。
1. Thread 的常見(jiàn)構(gòu)造方法
方法 | 作用 |
---|---|
Thread() | 創(chuàng)建線程對(duì)象 |
Thread(String name) | 創(chuàng)建線程對(duì)象,并命名 |
Thread(Runnable target) | 使用 Runnable 對(duì)象創(chuàng)建線程對(duì)象 |
Thread(Runnable target, String name) | 使用 Runnable 對(duì)象創(chuàng)建線程對(duì)象,并命名 |
class MyRunnable implements Runnable{@Overridepublic void run() {}
}public class demo1 {public static void main(String[] args) {Thread t1 = new Thread();System.out.println(t1.getName());Thread t2 = new Thread(new MyRunnable());System.out.println(t2.getName());Thread t3 = new Thread("t3線程");System.out.println(t3.getName());Thread t4 = new Thread(new MyRunnable(), "t4線程");System.out.println(t4.getName());}
}
運(yùn)行結(jié)果:
2. Thread 類(lèi)常見(jiàn)屬性
屬性 | 方法 |
---|---|
ID | getId() |
名稱(chēng) | getName() |
狀態(tài) | getState() |
優(yōu)先級(jí) | getPriority() |
是否后臺(tái)線程 | isDaemon() |
是否存活 | isAlive() |
是否被中斷 | isInterruupted() |
2.1 ID
ID 是線程的唯?標(biāo)識(shí),不同線程不會(huì)重復(fù)
public class demo2 {public static void main(String[] args) {Thread t1 = new Thread();System.out.println(t1.getName() + "ID:" + t1.getId());Thread t2 = new Thread("t2線程");System.out.println(t2.getName() + "ID:" + t2.getId());}
}
運(yùn)行結(jié)果:
【注意】:這里的 ID 和 pcb 一一對(duì)應(yīng),但是這里的 ID 和 系統(tǒng)的中 pcb 上的 ID 是不同的體系(Java代碼無(wú)法獲取到 pcb 中的 ID),JVM 自己搞了一套 ID 體系
比如:我們?nèi)ド习?#xff0c;在A公司,你的是工號(hào)xxxx,后來(lái)去到了B公司,你的工號(hào)是yyyy,人都是同一個(gè)人,在不同的體系中,工號(hào)就變了
2.2 名稱(chēng)
public class demo2 {public static void main(String[] args) {Thread t1 = new Thread();System.out.println(t1.getName());Thread t2 = new Thread("t2線程");System.out.println(t2.getName());Thread t3 = new Thread();t3.setName("t3線程"); // 設(shè)置線程名稱(chēng)System.out.println(t3.getName());}
}
運(yùn)行結(jié)果:
如果線程沒(méi)有命名, 默認(rèn)為 Thread-0, Thread-1...
2.3 狀態(tài)
后面具體介紹…(下集預(yù)告)
2.4 優(yōu)先級(jí)
雖然 Java 提供了優(yōu)先級(jí)接口,實(shí)際上就算修改了優(yōu)先級(jí),現(xiàn)象也不明顯,修改了優(yōu)先級(jí)是一回事,系統(tǒng)調(diào)度又是另一回事,這里的優(yōu)先級(jí)只能是一個(gè)“建議參考”,具體還是系統(tǒng)以自身為準(zhǔn)。
本質(zhì)上還是因?yàn)?strong>調(diào)度這個(gè)事情,系統(tǒng)就一言堂了,我們很難干預(yù)到。
public class demo9 {public static void main(String[] args) {Thread t1 = new Thread(() -> {while (true) {System.out.println("hello Thread1");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}});Thread t2 = new Thread(() -> {while (true) {System.out.println("hello Thread2");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}});t1.setPriority(Thread.MIN_PRIORITY); // 設(shè)置最低優(yōu)先級(jí)t2.setPriority(Thread.MAX_PRIORITY); // 設(shè)置最高優(yōu)先級(jí)t1.start();t2.start();}
}
運(yùn)行結(jié)果:
從上圖可以看出無(wú)論是否設(shè)置優(yōu)先級(jí),運(yùn)行結(jié)果都差不多
2.5 是否后臺(tái)線程
前臺(tái)線程: 這種線程如果不運(yùn)行結(jié)束的話, 此時(shí) Java 進(jìn)程是一定不會(huì)結(jié)束的
后臺(tái)線程: 這樣的線程, 即使繼續(xù)在執(zhí)行, 也不能阻止 Java 進(jìn)程結(jié)束
舉例: 酒桌文化
人物: 組局人(前臺(tái)線程) 小楊(后臺(tái)線程)
一桌人吃飯, 組局人(前臺(tái)線程)可以掌握整個(gè)宴席(線程)的結(jié)束, 當(dāng)組局人(前臺(tái)線程)說(shuō)宴席(線程)結(jié)束就結(jié)束了, 即使小楊(后臺(tái)線程)還沒(méi)有吃完,即使我還沒(méi)有吃飽,也得撤了(當(dāng)有多個(gè)組局人(多個(gè)前臺(tái)線程)的時(shí)候, 當(dāng)全部的組局人都不吃了, 宴席(線程)就結(jié)束了), 如果小楊先吃完,我想先溜(后臺(tái)線程結(jié)束),我溜了對(duì)于整個(gè)宴席沒(méi)有任何影響.
當(dāng)全部的前臺(tái)線程都結(jié)束了, 線程就結(jié)束了, 無(wú)論后臺(tái)線程是否執(zhí)行結(jié)束
當(dāng)后臺(tái)線程執(zhí)行結(jié)束了, 要等到全部的前臺(tái)線程結(jié)束, 線程才結(jié)束
在 Java 代碼中, main 線程就是前臺(tái)線程, 另外創(chuàng)建出來(lái)的線程也是前臺(tái)線程, 可以通過(guò) setDaemon
方法把線程設(shè)置為后臺(tái)線程.
代碼:
public class demo10 {public static void main(String[] args) {Thread t1 = new Thread(() -> {for (int i = 0; i < 5; i++) {System.out.println("hello Thread1");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}});t1.setDaemon(true); // t1線程設(shè)置為后臺(tái)線程t1.start();}
}
運(yùn)行結(jié)果:
【注意】:此處也有一定概率,出現(xiàn) t1 打印一次,然后結(jié)束進(jìn)程的情況
這種情況就要看是 main 先執(zhí)行結(jié)束,還是 t1 先執(zhí)行打印1一次(線程之間是搶占式執(zhí)行的,調(diào)度順序是不確定的)
2.6 是否存活
是否存活: 指的是系統(tǒng)中(pcb) 是否還存在
Thread
對(duì)象的生命周期和 pcb 的生命周期是不一定完全一樣的
代碼:
public class demo11 {public static void main(String[] args) {Thread t1 = new Thread(() -> {try {Thread.sleep(2000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("線程執(zhí)行完畢!");});// 判斷 t1線程是否存活System.out.println(t1.isAlive());t1.start();System.out.println(t1.isAlive());// 等待線程執(zhí)行結(jié)束try {t1.join();} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(t1.isAlive());}
}
運(yùn)行結(jié)果:
2.7 是否被中斷
中斷線程,在 Java 中,都只是“提醒”,“建議”,真正要不要終止,還得線程本體來(lái)進(jìn)行決定的
t1線程正在執(zhí)行,其他線程,只能提醒一下 t1 是不是要終止了,t1 收到這樣的提醒之后,也還是得自己決定的
常見(jiàn)的方式以下兩種:
- 通過(guò)共享的標(biāo)記來(lái)進(jìn)行溝通
- 調(diào)用
interrupt()
方法來(lái)通知
示例一:
public class demo12 {private static boolean isRunning = true;public static void main(String[] args) {Thread t1 = new Thread(() -> {while (isRunning) {System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println("t1線程結(jié)束");});t1.start(); // 啟動(dòng)線程// 等待3stry {Thread.sleep(3000);} catch (InterruptedException e) {throw new RuntimeException(e);}// 3s 后, 主線程修改 isRunning 的值,從而通知 t1 結(jié)束System.out.println("控制 t1 線程結(jié)束");isRunning = false;}
}
運(yùn)行結(jié)果:
示例二:
public class demo13 {public static void main(String[] args) {Thread t1 = new Thread(() -> {while (!Thread.currentThread().isInterrupted()) {System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {//throw new RuntimeException(e);//e.printStackTrace();System.out.println("線程即將結(jié)束");break; // !!!注意此處的break}}System.out.println("t1線程結(jié)束");});t1.start();try {Thread.sleep(3000);} catch (InterruptedException e) {throw new RuntimeException(e);}t1.interrupt();}
}
運(yùn)行結(jié)果:
Thread
收到通知的方式有兩種:
- 如果線程因?yàn)檎{(diào)?
wait/join/sleep
等?法?阻塞掛起,則以InterruptedException
異常的形式通知,清除中斷標(biāo)志- 當(dāng)出現(xiàn)
InterruptedException
的時(shí)候, 要不要結(jié)束線程取決于catch
中代碼的寫(xiě)法. 可以選擇忽略這個(gè)異常, 也可以跳出循環(huán)結(jié)束線程.
- 當(dāng)出現(xiàn)
- 否則,只是內(nèi)部的?個(gè)中斷標(biāo)志被設(shè)置,
Thread
可以通過(guò)Thread.currentThread().isInterrupted()
判斷指定線程的中斷標(biāo)志被設(shè)置,不清除中斷標(biāo)志
這種方式通知收到的更及時(shí),即使線程正在 sleep 也可以馬上收到。
3. 啟動(dòng)線程-start()
之前我們已經(jīng)看到了如何通過(guò)重寫(xiě) run()
方法創(chuàng)建?個(gè)線程對(duì)象,但線程對(duì)象被創(chuàng)建出來(lái)并不意味著線程就開(kāi)始運(yùn)行了。
舉例
- 重寫(xiě)
run()
方法是提供給線程要做的事情的指令清單- 線程對(duì)象可以認(rèn)為是把 小楊、肯德滑稽叫過(guò)來(lái)點(diǎn)餐
- 而調(diào)用
start()
方法,,就是喊一聲“去制作吧”,線程才真正獨(dú)立來(lái)執(zhí)行
調(diào)用 start()
方法, 才真的在操作系統(tǒng)的底層創(chuàng)建出一個(gè)線程.