wordpress禁用php報(bào)錯(cuò)湖南seo推廣系統(tǒng)
阿華代碼,不是逆風(fēng),就是我瘋,你們的點(diǎn)贊收藏是我前進(jìn)最大的動(dòng)力!!7000字長(zhǎng)文,希望本文內(nèi)容能夠幫助到你!
目錄
一:創(chuàng)建線程五種方式
方式一:繼承Thread類,再實(shí)例化
?方式二:實(shí)現(xiàn)Runnable接口,重寫(xiě)run方法
方式三:匿名內(nèi)部類寫(xiě)法
方式四:Runnable+匿名內(nèi)部類
方式五:lambda表達(dá)式
二:Thread常見(jiàn)方法
1:Thread方法
2:獲取Thread屬性的方法?
(1)守護(hù)進(jìn)程
(2).setDaemon()方法
①前臺(tái)/后臺(tái)線程
②.setDaemon
③結(jié)果分析:
(3)isAlive()
(4)start方法和run方法的區(qū)別
三:如何提前終止一個(gè)線程
1:標(biāo)志位——isQuit
(1)變量捕獲:重點(diǎn)重點(diǎn)重點(diǎn)
(2)lambda復(fù)制和傳參理解
2:Thread內(nèi)置變量isinterrupted
(1)isinterrupted本質(zhì)
(2)sleep清空標(biāo)志符
(3)解決方式(catch中加代碼)
一:創(chuàng)建線程五種方式
方式一:繼承Thread類,再實(shí)例化
package thread;/*** Created with IntelliJ IDEA.* Description:* User: Hua YY* Date: 2024-09-17* Time: 14:20*/
class MyThread extends Thread{@Overridepublic void run() {System.out.println("這就是進(jìn)入該線程的入口");}
}
public class ThreadDemo1 {public static void main(String[] args) {//根據(jù)類,創(chuàng)建實(shí)例,線程實(shí)例才是真正的線程//一般用向上轉(zhuǎn)型的寫(xiě)法Thread t = new MyThread();t.start();}
}
?方式二:實(shí)現(xiàn)Runnable接口,重寫(xiě)run方法
package thread;/*** Created with IntelliJ IDEA.* Description:* User: Hua YY* Date: 2024-09-19* Time: 9:20*/
class MyTread3 implements Runnable{@Overridepublic void run() {while(true){System.out.println("這里是run線程");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}
public class TreadDome3 {public static void main(String[] args) {Runnable runnable = new MyTread3();//相當(dāng)于借刀殺人了Thread t = new Thread(runnable);t.start();while(true){System.out.println("這里是main函數(shù)線程");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}}
注:可以通過(guò)Runnable這個(gè)接口,可以抽象出一段被其他實(shí)體執(zhí)行的代碼,還是需要搭配Thread類來(lái)進(jìn)行使用
方式三:匿名內(nèi)部類寫(xiě)法
在實(shí)例化Thread對(duì)象時(shí){}里創(chuàng)建匿名內(nèi)部類,重寫(xiě)run方法
匿名內(nèi)部類:
①?zèng)]有名字,不能重復(fù)使用
②這個(gè)新的類繼承自Thread,并且{}里可以定義子類的屬性和方法
③t的指向不僅僅是Thread,還有它的子類(雖然沒(méi)名字),(即不僅是Thread的實(shí)例,也是其子類的實(shí)例)
package thread;/*** Created with IntelliJ IDEA.* Description:* User: Hua YY* Date: 2024-09-19* Time: 9:39*/ public class ThreadDome4 {public static void main(String[] args) {Thread thread = new Thread(){public void run(){while(true){System.out.println("這里是由匿名內(nèi)部類實(shí)現(xiàn)的線程");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}};thread.start();while(true){System.out.println("這里是main函數(shù)入口");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}} }
方式四:Runnable+匿名內(nèi)部類
實(shí)現(xiàn)Runnable接口,重寫(xiě)run方法實(shí)現(xiàn)匿名內(nèi)部類
package thread;/*** Created with IntelliJ IDEA.* Description:* User: Hua YY* Date: 2024-09-19* Time: 10:07*/
public class ThreadDome5 {public static void main(String[] args) {Thread thread = new Thread(new Runnable() {@Overridepublic void run() {while(true){System.out.println("run method");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}});thread.start();while(true){System.out.println("main method");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}}
方式五:lambda表達(dá)式
lambda表達(dá)式,適合簡(jiǎn)單直觀的代碼,如果代碼過(guò)于復(fù)雜還是需要提取出來(lái)的
在Java中方法的實(shí)現(xiàn)依賴于類,方法不能脫離類單獨(dú)存在,這里就導(dǎo)致為了設(shè)置回調(diào)函數(shù),不得不套上一層類,但是并不常用——引出了lambda表達(dá)式。
函數(shù)式接口相當(dāng)于在沒(méi)有破壞java原有的規(guī)則上(方法不能脫離類單獨(dú)存在),單獨(dú)給lambda一個(gè)解釋
第一個(gè)標(biāo)記的紅色方框中的()->? ,()括號(hào)中可以帶參數(shù)
package thread;/*** Created with IntelliJ IDEA.* Description:* User: Hua YY* Date: 2024-09-19* Time: 10:29*/
public class ThreadDome55 {public static void main(String[] args) {Thread thread = new Thread(()->{while (true){System.out.println("run method");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}});thread.start();while(true){System.out.println("main method");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}}
二:Thread常見(jiàn)方法
1:Thread方法
2:獲取Thread屬性的方法?
后面的代碼中會(huì)運(yùn)用到,有相應(yīng)的解釋
(1)守護(hù)進(jìn)程
通過(guò)之前的學(xué)習(xí),我們知道,main方法走完了,整個(gè)進(jìn)程就結(jié)束了。 現(xiàn)在我們引入了線程的概念,那這個(gè)結(jié)論還準(zhǔn)確嗎。有沒(méi)有例外呢??
下面我們舉例:代碼里面我們創(chuàng)建main函數(shù)線程
這里我們使用jconsole工具來(lái)輔助(上一篇博客有講怎么使用jconsole前面)
package thread;/*** Created with IntelliJ IDEA.* Description:* User: Hua YY* Date: 2024-09-19* Time: 10:58*/
public class ThreadDome6 {public static void main(String[] args) {Thread thread = new Thread(new Runnable() {@Overridepublic void run() {while(true){System.out.println("run method");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}} , "這個(gè)線程的名字叫:測(cè)試");thread.start();}}
我們可以發(fā)現(xiàn)jconsole線程運(yùn)行詳細(xì)信息中,沒(méi)有main函數(shù),但是有我們的測(cè)試線程,很明顯即使main函數(shù)這個(gè)前臺(tái)線程已經(jīng)結(jié)束了,但是這個(gè)進(jìn)程依舊還在運(yùn)行(可以說(shuō)是這個(gè)“這個(gè)線程的名字叫:測(cè)試”的線程還在運(yùn)行)
由此我們引出一組概念:前臺(tái)線程和后臺(tái)線程
(2).setDaemon()方法
①前臺(tái)/后臺(tái)線程
重點(diǎn):咱們創(chuàng)建的線程,默認(rèn)都是前臺(tái)線程,會(huì)阻止進(jìn)程的結(jié)束,只要前臺(tái)線程沒(méi)有執(zhí)行完,進(jìn)程就不會(huì)結(jié)束,即使main函數(shù)這個(gè)線程已經(jīng)執(zhí)行完畢
(這么理解:后臺(tái)進(jìn)程沒(méi)有話語(yǔ)權(quán),只要還有前臺(tái)線程,進(jìn)程就不會(huì)結(jié)束)
②.setDaemon
理解:Daemon是守護(hù)的意思,這個(gè)方法是把某線程設(shè)置為后臺(tái)線程(守護(hù)線程)
注:這個(gè)方法一定要在“.start”方法之前設(shè)置
接上文,我們引入.setDaemon()方法,可以將Thread下的線程從前臺(tái)改為后臺(tái),下面會(huì)詳細(xì)解釋兩者區(qū)別。
③結(jié)果分析:
什么都沒(méi)有打印是因?yàn)?#xff0c;我們把main函數(shù)設(shè)置為了后臺(tái)線程,這個(gè)線程走完了,那整個(gè)進(jìn)程都結(jié)束了,Thread這個(gè)前臺(tái)線程
(3)isAlive()
isAlive(),方法,表示了當(dāng)前內(nèi)核中的線程(pcb)是否還存在,內(nèi)核中的線程和實(shí)例的周期是不一致的
①在創(chuàng)建完Thread對(duì)象之后,start方法之前,pcb還沒(méi)有創(chuàng)建出來(lái),所以答疑結(jié)果為false
②在start方法之后,線程結(jié)束之前,對(duì)象存在,pcb存在,打印結(jié)果為true,
③線程run完了,pcb得到釋放,為false
④注意下面的代碼Thread.sleep(5000) ,如果沉睡時(shí)間改為3000ms以下,那么最后一條打印結(jié)果就不確定了,線程的隨機(jī)調(diào)度
package thread;/*** Created with IntelliJ IDEA.* Description:* User: Hua YY* Date: 2024-09-19* Time: 18:24*/
public class ThreadDemon8 {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(()->{try {Thread.sleep(3000);} catch (InterruptedException e) {throw new RuntimeException(e);}});System.out.println(thread.isAlive());//false,有對(duì)象,無(wú)pcb線程thread.start();//創(chuàng)建線程System.out.println(thread.isAlive());//true,有對(duì)象,有pcbThread.sleep(5000);//main函數(shù)線程沉睡5s,此時(shí)Thread線程3s沉睡完了,thread線程結(jié)束,thread對(duì)象還在System.out.println(thread.isAlive());//false}}
(4)start方法和run方法的區(qū)別
start方法核心是創(chuàng)建一個(gè)新的線程,但是run方法僅僅是一個(gè)方法、一個(gè)線程的入口,類似main方法的入口,兩者不能說(shuō)沒(méi)有關(guān)系,簡(jiǎn)直是毫無(wú)關(guān)系!!!
package thread;/*** Created with IntelliJ IDEA.* Description:* User: Hua YY* Date: 2024-09-19* Time: 18:56*/
public class ThreadDemon9 {public static void main(String[] args) {Thread t1 = new Thread(){@Overridepublic void run() {while(true){try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("run線程方法正在執(zhí)行");}}};//t1.run();//不屏蔽這行代碼,將會(huì)一直死循環(huán)在run方法中,單線程main的t1.start();System.out.println("main函數(shù)線程正在執(zhí)行");}}
三:如何提前終止一個(gè)線程
1:標(biāo)志位——isQuit
我們需要在Thread實(shí)例化中寫(xiě)符合能夠控制線程的結(jié)構(gòu),下面的代碼我們引入isQuit這個(gè)靜態(tài)成員變量,來(lái)控制while循環(huán),進(jìn)而達(dá)到提前終止線程這樣一個(gè)目的
/*** Created with IntelliJ IDEA.* Description:* User: Hua YY* Date: 2024-09-19* Time: 19:18*/
public class ThreadDemon12 {private static boolean isQuit = false;public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(()->{while(!isQuit){try {Thread.sleep(500);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("t1線程正在運(yùn)行");}});t1.start();Thread.sleep(2001);isQuit = true;System.out.println("終止t1線程");}}
(1)變量捕獲:重點(diǎn)重點(diǎn)重點(diǎn)
提問(wèn):上述代碼能否將isQuit這個(gè)變量在main方法中定義(局部變量)。不行
在lambda匿名內(nèi)部類當(dāng)中有一條規(guī)定:lambda匿名內(nèi)部類可以獲取外面定義的成員變量(本質(zhì)是將外面的成員變量作為參數(shù)傳進(jìn)來(lái),這個(gè)被捕獲的(變量)參數(shù)必須是final,或者“事實(shí)final”)
大前提這個(gè)變量定義在main函數(shù)內(nèi)部
零:解釋“事實(shí)final”
定義的成員變量雖然沒(méi)有被final修飾,但是這個(gè)成員變量沒(méi)有被修改過(guò)(有點(diǎn)那種“雖無(wú)夫妻之名,但有夫妻之實(shí)”的感覺(jué))。
舉例1:在mian函數(shù)內(nèi)部定義??不加final修飾? ?的局部變量(可行)
舉例2:在mian函數(shù)內(nèi)部定義??不加final修飾? 的局部變量??并且修改isQuit的值(不可行,lambda報(bào)錯(cuò))
舉例3:在mian函數(shù)內(nèi)部定義??加final修飾? 的局部變量??并且修改isQuit的值(不可行,final報(bào)錯(cuò))
(2)lambda復(fù)制和傳參理解
承接舉例1:我們刪除isQuit這一行代碼
我們都知道,main函數(shù)執(zhí)行完畢,那么main函數(shù)中定義的局部變量會(huì)進(jìn)行回收,但是在上述兩個(gè)線程中,main方法結(jié)束了,isQuit已經(jīng)被回收了,這個(gè)Thread(t1)線程為什么還能運(yùn)行(他線程用到了isQuit作為循環(huán)判斷條件)。
總結(jié):這里是因?yàn)?#xff0c;lambda獲得的成員變量,是作為參數(shù)傳進(jìn)來(lái)的(可以理解為復(fù)制拷貝,是一個(gè)全新的個(gè)體),main方法執(zhí)行完了,isQuit的棧幀就銷毀了,但是Thread(t1)中拷貝過(guò)來(lái)的isQuit所創(chuàng)建的棧幀還在呀!!!
。
2:Thread內(nèi)置變量isinterrupted
(1)isinterrupted本質(zhì)
利用Thread類的實(shí)例內(nèi)部成員變量,來(lái)取代我們?cè)?中使用的,手動(dòng)創(chuàng)建的靜態(tài)成員變量isQuit
package thread;/*** Created with IntelliJ IDEA.* Description:* User: Hua YY* Date: 2024-09-20* Time: 10:23*/
public class ThreadDemon13 {public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(()->{while(!Thread.currentThread().isInterrupted()){ //當(dāng)t1.interrupt();生效,循環(huán)條件為false,被打斷了try {Thread.sleep(500);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("t1線程正在運(yùn)行");}});t1.start();Thread.sleep(2001);t1.interrupt();//讓t1被打斷,相當(dāng)于isQuit = trueSystem.out.println("終止t1線程");}
}
?(2)sleep清空標(biāo)志符
結(jié)果分析——
目的:給程序員創(chuàng)造更多的“可操作空間”
運(yùn)行上述代碼,報(bào)錯(cuò),這是因?yàn)?#xff0c;我們的中斷了t1線程的sleep(提前喚醒會(huì)做兩件事:1:清空標(biāo)志符,2:拋出InterruptedException異常),sleep把interrupted又設(shè)置回false,進(jìn)而while循環(huán)判定條件變成true,最后被catch捕獲中斷異常。
(3)解決方式(catch中加代碼)
①讓線程立即結(jié)束:加上break;
②讓線程不結(jié)束:不加break,讓它報(bào)錯(cuò)
③讓線程執(zhí)行一些代碼后再結(jié)束:寫(xiě)一些其它代碼后,再break。