實(shí)現(xiàn)多線程方式有三種:
1.繼承Thread 復(fù)寫run方法???????????? 無(wú)返回值
2.實(shí)現(xiàn)Runnable接口復(fù)寫run方法窗轩,調(diào)用thread類的start開啟? 無(wú)返回值
3.實(shí)現(xiàn)callable(指定泛型類)接口實(shí)現(xiàn)call方法绍撞,創(chuàng)建FutureTask類傳入callable實(shí)例翅雏,創(chuàng)建thread類傳入futureTask實(shí)例調(diào)用start方法開啟? 有返回值
Thread與runnable關(guān)系
發(fā)現(xiàn)在多線程實(shí)現(xiàn)過程中有三種做法棍矛,thread類 runnable接口蕴掏,從代碼結(jié)構(gòu)本身來(lái)講使用runnable是最方便的门坷,因?yàn)槠淇梢员苊鈫卫^承的局限默勾,用時(shí)也可以更好的進(jìn)行功能的擴(kuò)充休建。
thread類是runnable接口的字類乍恐,thread類子類實(shí)際復(fù)寫的是runnable接口的run方法评疗,
runnable與callable的區(qū)別?
1.runnable是JDK1.0的時(shí)候提出的多線程實(shí)現(xiàn)接口禁熏,而callable是JDK1.5之后提出的壤巷。
2.Runnable接口之中提供一個(gè)run方法,沒有返回值瞧毙。
callable接口提供call方法胧华,可以有返回值
想要實(shí)現(xiàn)多線程啟動(dòng),使用thread的start方法? 從古不變
多線程狀態(tài):
對(duì)于多線程開發(fā)而言宙彪,編寫程序的過程之中總是按照矩动,定義線程主體類,而后通過thread類進(jìn)行調(diào)用start释漆,線程就已經(jīng)開始運(yùn)行了悲没,因?yàn)檎w的線程處理有自己的一套運(yùn)行的狀態(tài):
???????? 創(chuàng)建-start開啟-就緒-阻塞-運(yùn)行狀態(tài)-終止。
1.任何一個(gè)線程的對(duì)象都應(yīng)該使用thread類進(jìn)行封裝男图,所以線程的啟動(dòng)使用的是start示姿,進(jìn)入到就緒狀態(tài)并沒有執(zhí)行,
2.進(jìn)入到就緒狀態(tài)后逊笆,就需要等待進(jìn)行資源調(diào)度栈戳,當(dāng)某一個(gè)程序調(diào)度成功后則進(jìn)度到運(yùn)行狀態(tài)run方法,但是所有的線程不可能一致持續(xù)執(zhí)行下去难裆,中間需要產(chǎn)生一些暫停的狀態(tài)子檀,列入:某線程執(zhí)行一段時(shí)間之后就需要讓出資源,而后這個(gè)線程就進(jìn)入阻塞狀態(tài)乃戈,隨后重新回到就緒狀態(tài)
3.當(dāng)run方法執(zhí)行完畢后褂痰,實(shí)際上該線程的主要任務(wù)也就結(jié)束了,那么此時(shí)就進(jìn)入到停止?fàn)顟B(tài)
start準(zhǔn)備執(zhí)行--》就緒狀態(tài)--》運(yùn)行狀態(tài)-》結(jié)束
多線程的主要操作方法都在thread類中定義的
線程的命名與的戎⒙恰:
???? 多線程的運(yùn)行狀態(tài)是不確定的缩歪,那么在程序的開發(fā)之中為了可以獲取到一些只能夠依靠線程的名字來(lái)進(jìn)行操作
??? 所以線程的名字是一個(gè)只管蟲咬的概念,這樣在thread類中就提供線程名稱的處理方式谍憔,構(gòu)造方法傳遞名字驶冒,設(shè)置名字的方法,獲取名字的方法韵卤。
??? 對(duì)于線程對(duì)象的獲取骗污,是不可能依靠一個(gè)this來(lái)完成的,因?yàn)榫€程的狀態(tài)不可控制沈条,但是有一點(diǎn)可以明確需忿,所有的線程對(duì)象一點(diǎn)要執(zhí)行run方法,那么這個(gè)時(shí)候我們可以考慮獲取當(dāng)前線程,在thread里面提供獲取當(dāng)前線程的方法屋厘,
線程休眠:
??? 如果說(shuō)現(xiàn)在希望某線程可以暫緩執(zhí)行一次涕烧,那么久可以使用休眠處理,在thread類中定義的休眠方法如下汗洒,
??? sleep方法
?? 休眠有可能被打斷议纯,一定要處理
休眠時(shí)間一到程序會(huì)立即恢復(fù)執(zhí)行
休眠的主要特點(diǎn)是可以自動(dòng)實(shí)現(xiàn)線程的喚醒,以繼續(xù)進(jìn)行后續(xù)的處理溢谤,但是需要注意的是瞻凤,如果現(xiàn)在有多個(gè)線程對(duì)象,那么休眠也有先后順序的
此時(shí)產(chǎn)生五個(gè)線程對(duì)象世杀,并且這五個(gè)現(xiàn)場(chǎng)對(duì)象執(zhí)行的方法體是相同的阀参,此時(shí)從我們程序執(zhí)行的感覺來(lái)講好像是若干個(gè)線程一起進(jìn)行休眠后,又一起喚醒執(zhí)行瞻坝,其實(shí)不是蛛壳,線程是隨機(jī)搶占Cpu資源,誰(shuí)先搶到誰(shuí)先執(zhí)行所刀。
線程中斷:
????? 在之前發(fā)現(xiàn)線程的休眠里面提供有一個(gè)中斷異常衙荐,實(shí)際上久證明線程的休眠是可以被打斷的,而這種打斷肯定是由其他線程完成的浮创。
在這個(gè)thread類里面提供又中斷執(zhí)行的處理方法
1.isInterrupted 是否被中斷
2.interrupt? 中斷線程
所有正在執(zhí)行的線程都是可以中斷的忧吟,中斷線程必須進(jìn)行異常處理
線程的同步與死鎖:
在多線程的處理之中,可以利用runnable描述多線程操作的資源蒸矛,而thread描述每一個(gè)線程對(duì)象瀑罗,于是當(dāng)多個(gè)線程訪問同一資源的時(shí)候如果處理不當(dāng)就會(huì)產(chǎn)生數(shù)據(jù)的錯(cuò)誤操作胸嘴。
方法同步關(guān)鍵字 :synchronized 同步代碼塊雏掠,同步方法兩種實(shí)現(xiàn)方式
線程的強(qiáng)制執(zhí)行:
所謂的線程的強(qiáng)制執(zhí)行指的是當(dāng)滿足某些條件后,某一個(gè)線程對(duì)象講可以一致獨(dú)占資源劣像,一直到該線程的程序執(zhí)行結(jié)束乡话,
線程禮讓:
線程的禮讓指先講線程的執(zhí)行權(quán)讓給別的線程先執(zhí)行,讓出執(zhí)行權(quán) 方y(tǒng)ield方法
禮讓執(zhí)行的時(shí)候耳奕,每次都會(huì)禮讓當(dāng)前資源
線程優(yōu)先級(jí):
從理論上來(lái)講線程的優(yōu)先級(jí)越高最先搶到CPU執(zhí)行權(quán)的幾率越高绑青,在thread類里賣弄針對(duì)優(yōu)先級(jí)有兩種處理方式
1.設(shè)置優(yōu)先級(jí)
2.獲取優(yōu)先級(jí)
在進(jìn)行優(yōu)先級(jí)定義的時(shí)候都是通過int類型的數(shù)字來(lái)完成的,而對(duì)于此數(shù)字的選擇在thread類里面久定義號(hào)了常量
最高優(yōu)先級(jí)MAX_PRIORITY?? 10
中級(jí)????? NORM??? 5
低級(jí)???? MAIN????? 1
所有線程默認(rèn)優(yōu)先級(jí)是中級(jí)
線程同步:
經(jīng)過分析之后已經(jīng)可以確認(rèn)同步問題鎖產(chǎn)生的主要問題屋群,那么下面就需要進(jìn)行同步問題的解決闸婴,但是解決同步問題的關(guān)鍵是鎖。
指的是當(dāng)某一個(gè)線程執(zhí)行操作的時(shí)候芍躏,其他線程只能在外面等待邪乍。
如果要想程序之中實(shí)現(xiàn)這把鎖的功能,需要使用關(guān)鍵字synchronized關(guān)鍵字來(lái)實(shí)現(xiàn),同步代碼塊庇楞,在同步代碼塊的操作里面代碼只允許一個(gè)線程執(zhí)行榜配,
1.利用同步代碼塊處理:
一般要進(jìn)行永不對(duì)象處理的時(shí)候采用當(dāng)前對(duì)象this進(jìn)行同步
加入同步處理之后,程序的整體性能能下降了吕晌,同步實(shí)際上會(huì)造成性能的降低
2.利用同步方法解決蛋褥,只需要在方法定義上使用synchronization關(guān)鍵字修飾即可
在Java原生類庫(kù)的時(shí)候會(huì)發(fā)現(xiàn),系統(tǒng)中許多的類上使用的同步處理采用的都是同步方法睛驳,但是千萬(wàn)記住同步會(huì)造成性能下降
死鎖的概念:
死鎖是在進(jìn)行多線程同步處理之中有可能產(chǎn)生的一種問題烙心。
所謂的死鎖指的是若干個(gè)線程彼此互相等待的狀態(tài)。
在多線程開發(fā)過程之中最為著名的案例就是生產(chǎn)者與消費(fèi)者的操作柏靶,操作流程如下
1.生產(chǎn)者負(fù)責(zé)內(nèi)容的生產(chǎn)
2.每當(dāng)生產(chǎn)者生產(chǎn)完成一項(xiàng)完整的內(nèi)容之后消費(fèi)者要從這里取走內(nèi)容
3.如果生產(chǎn)者沒有生產(chǎn)完成則消費(fèi)者需要等待他生產(chǎn)完成才能消費(fèi)弃理,如果消費(fèi)者還沒有對(duì)內(nèi)容進(jìn)行消費(fèi),生產(chǎn)者需要等待消費(fèi)者 消費(fèi)完成之后在進(jìn)行生產(chǎn)
解決數(shù)據(jù)同步問題:
如果要解決問題屎蜓,首先解決的就是數(shù)據(jù)同步的處理問題痘昌,如果要想解決數(shù)據(jù)同步最簡(jiǎn)單的方式就是同步代碼塊或者同步方法。
但是同步不能解決數(shù)據(jù)重復(fù)問題炬转,只能保證執(zhí)行順序是一個(gè)一個(gè)的執(zhí)行并不會(huì)并發(fā)處理
解決方案是線程等待與喚醒機(jī)制
如果說(shuō)現(xiàn)在想要解決生產(chǎn)者與消費(fèi)者的問題辆苔,那么最好的解決方案就是使用等待與喚醒機(jī)制,而對(duì)于等待與喚醒機(jī)制主要依賴的是object類的方法處理
方法1扼劈,wait? 等待
方法2 notify? 喚醒
方法3 notifyAll 喚醒全部
優(yōu)雅的停止線程:
在多線程操作之中如果要啟動(dòng)多線程肯定是使用thread類的start方法驻啤,而如果對(duì)于多線程需要進(jìn)行停止處理荐吵,thread類原本提供有stop方法,但是stop方法在1.2的時(shí)候已經(jīng)被廢除了先煎,也不將建議在代碼中使用stop方法。
stop? destroysuspend resume這些方法1.2都被廢除了 不建議使用
想要實(shí)現(xiàn)多線程停止需要通過一種柔和的方式進(jìn)行處理薯蝎,自定義屬性進(jìn)行判斷修改
線程守護(hù):
現(xiàn)在假設(shè)有一個(gè)人并且這個(gè)人有一個(gè)保鏢遥倦,這個(gè)保鏢一定是在這個(gè)人活著的時(shí)候進(jìn)行守護(hù)的,如果這個(gè)人已經(jīng)死了額占锯,保鏢也就沒有作用了,
所以在多線程里面進(jìn)行守護(hù)線程的定義堡称,也就是說(shuō)如果現(xiàn)在主線程的程序或者其他線程還在執(zhí)行的時(shí)候,那么外面的守護(hù)線程就一直存在艺演,并且允許在后臺(tái)狀態(tài)却紧,
setDaemon? true 就是設(shè)置守護(hù)線程方法婿失。
isDaemon? 是否是守護(hù)線程
可以發(fā)現(xiàn)所有的守護(hù)線程都是圍繞用戶線程執(zhí)行的,如果用戶線程執(zhí)行完畢豪硅,守護(hù)線程也就消失了挺物,在JVM里面最大的守護(hù)線程就是GC線程,程序執(zhí)行中GC線程會(huì)一直存在识藤,如果程序執(zhí)行完畢,GC線程也就消失
volatile直接內(nèi)存操作:
面試題:請(qǐng)解釋volatile與synchronized的區(qū)別稽穆?
volatile主要在屬性上使用,而synchronized是在代碼塊與方法上使用的
volatile無(wú)法描述同步處理舌镶,它只是一種直接內(nèi)存的處理豪娜,避免了副本的操作,而synchronized是實(shí)現(xiàn)同步操作的
volatile它可以更快的表示變量的修改和處理