摘要:現(xiàn)在已經(jīng)沒(méi)有強(qiáng)制線程終止的方法了由于方法可以讓一個(gè)線程終止掉另一個(gè)線程被終止的線程會(huì)立即釋放鎖,這可能會(huì)讓對(duì)象處于不一致的狀態(tài)。
前言
昨天已經(jīng)寫了:
多線程三分鐘就可以入個(gè)門了!
如果沒(méi)看的同學(xué)建議先去閱讀一遍哦~
在寫文章之前通讀了一遍《Java 核心技術(shù) 卷一》的并發(fā)章節(jié)和《Java并發(fā)編程實(shí)戰(zhàn)》前面的部分,回顧了一下以前寫過(guò)的筆記。從今天開(kāi)始進(jìn)入多線程的知識(shí)點(diǎn)咯~
我其實(shí)也是相當(dāng)于從零開(kāi)始學(xué)多線程的,如果文章有錯(cuò)的地方還請(qǐng)大家多多包含,不吝在評(píng)論區(qū)下指正呢~~
一、Thread線程類API聲明本文使用的是JDK1.8
實(shí)現(xiàn)多線程從本質(zhì)上都是由Thread類來(lái)進(jìn)行操作的~我們來(lái)看看Thread類一些重要的知識(shí)點(diǎn)。Thread這個(gè)類很大,不可能整個(gè)把它看下來(lái),只能看一些常見(jiàn)的、重要的方法。
頂部注釋的我們已經(jīng)解析過(guò)了,如果不知道的同學(xué)可前往:多線程三分鐘就可以入個(gè)門了!
1.1設(shè)置線程名我們?cè)谑褂枚嗑€程的時(shí)候,想要查看線程名是很簡(jiǎn)單的,調(diào)用Thread.currentThread().getName()即可。
如果沒(méi)有做什么的設(shè)置,我們會(huì)發(fā)現(xiàn)線程的名字是這樣子的:主線程叫做main,其他線程是Thread-x
下面我就帶著大家來(lái)看看它是怎么命名的:
nextThreadNum()的方法實(shí)現(xiàn)是這樣的:
基于這么一個(gè)變量-->線程初始化的數(shù)量
點(diǎn)進(jìn)去看到init方法就可以確定了:
看到這里,如果我們想要為線程起個(gè)名字,那也是很簡(jiǎn)單的。Thread給我們提供了構(gòu)造方法!
下面我們來(lái)測(cè)試一下:
實(shí)現(xiàn)了Runnable的方式來(lái)實(shí)現(xiàn)多線程:
public class MyThread implements Runnable { @Override public void run() { // 打印出當(dāng)前線程的名字 System.out.println(Thread.currentThread().getName()); } }
測(cè)試:
public class MyThreadDemo { public static void main(String[] args) { MyThread myThread = new MyThread(); //帶參構(gòu)造方法給線程起名字 Thread thread1 = new Thread(myThread, "關(guān)注公眾號(hào)Java3y"); Thread thread2 = new Thread(myThread, "qq群:742919422"); thread1.start(); thread2.start(); // 打印當(dāng)前線程的名字 System.out.println(Thread.currentThread().getName()); } }
結(jié)果:
當(dāng)然了,我們還可以通過(guò)setName(String name)的方法來(lái)改掉線程的名字的。我們來(lái)看看方法實(shí)現(xiàn);
檢查是否有權(quán)限修改:
至于threadStatus這個(gè)狀態(tài)屬性,貌似沒(méi)發(fā)現(xiàn)他會(huì)在哪里修改:
1.2守護(hù)線程守護(hù)線程是為其他線程服務(wù)的
垃圾回收線程就是守護(hù)線程~
守護(hù)線程有一個(gè)特點(diǎn):
當(dāng)別的用戶線程執(zhí)行完了,虛擬機(jī)就會(huì)退出,守護(hù)線程也就會(huì)被停止掉了。
也就是說(shuō):守護(hù)線程作為一個(gè)服務(wù)線程,沒(méi)有服務(wù)對(duì)象就沒(méi)有必要繼續(xù)運(yùn)行了
使用線程的時(shí)候要注意的地方
在線程啟動(dòng)前設(shè)置為守護(hù)線程,方法是setDaemon(boolean on)
使用守護(hù)線程不要訪問(wèn)共享資源(數(shù)據(jù)庫(kù)、文件等),因?yàn)樗赡軙?huì)在任何時(shí)候就掛掉了。
守護(hù)線程中產(chǎn)生的新線程也是守護(hù)線程
測(cè)試一波:
public class MyThreadDemo { public static void main(String[] args) { MyThread myThread = new MyThread(); //帶參構(gòu)造方法給線程起名字 Thread thread1 = new Thread(myThread, "關(guān)注公眾號(hào)Java3y"); Thread thread2 = new Thread(myThread, "qq群:742919422"); // 設(shè)置為守護(hù)線程 thread2.setDaemon(true); thread1.start(); thread2.start(); System.out.println(Thread.currentThread().getName()); } }
上面的代碼運(yùn)行多次可以出現(xiàn)(電腦性能足夠好的同學(xué)可能測(cè)試不出來(lái)):線程1和主線程執(zhí)行完了,我們的守護(hù)線程就不執(zhí)行了~
原理:這也就為什么我們要在啟動(dòng)之前設(shè)置守護(hù)線程了。
1.3優(yōu)先級(jí)線程線程優(yōu)先級(jí)高僅僅表示線程獲取的CPU時(shí)間片的幾率高,但這不是一個(gè)確定的因素!
線程的優(yōu)先級(jí)是高度依賴于操作系統(tǒng)的,Windows和Linux就有所區(qū)別(Linux下優(yōu)先級(jí)可能就被忽略了)~
可以看到的是,Java提供的優(yōu)先級(jí)默認(rèn)是5,最低是1,最高是10:
實(shí)現(xiàn):
setPriority0是一個(gè)本地(navite)的方法:
private native void setPriority0(int newPriority);1.4線程生命周期
在上一篇介紹的時(shí)候其實(shí)也提過(guò)了線程的線程有3個(gè)基本狀態(tài):執(zhí)行、就緒、阻塞
在Java中我們就有了這個(gè)圖,Thread上很多的方法都是用來(lái)切換線程的狀態(tài)的,這一部分是重點(diǎn)!
其實(shí)上面這個(gè)圖是不夠完整的,省略掉了一些東西。后面在講解的線程狀態(tài)的時(shí)候我會(huì)重新畫(huà)一個(gè)~
下面就來(lái)講解與線程生命周期相關(guān)的方法~
1.4.1sleep方法調(diào)用sleep方法會(huì)進(jìn)入計(jì)時(shí)等待狀態(tài),等時(shí)間到了,進(jìn)入的是就緒狀態(tài)而并非是運(yùn)行狀態(tài)!
于是乎,我們的圖就可以補(bǔ)充成這樣:
1.4.2yield方法調(diào)用yield方法會(huì)先讓別的線程執(zhí)行,但是不確保真正讓出
意思是:我有空,可以的話,讓你們先執(zhí)行
于是乎,我們的圖就可以補(bǔ)充成這樣:
1.4.3join方法調(diào)用join方法,會(huì)等待該線程執(zhí)行完畢后才執(zhí)行別的線程~
我們進(jìn)去看看具體的實(shí)現(xiàn):
wait方法是在Object上定義的,它是native本地方法,所以就看不了了:
wait方法實(shí)際上它也是計(jì)時(shí)等待(如果帶時(shí)間參數(shù))的一種!,于是我們可以補(bǔ)充我們的圖:
1.4.3interrupt方法線程中斷在之前的版本有stop方法,但是被設(shè)置過(guò)時(shí)了?,F(xiàn)在已經(jīng)沒(méi)有強(qiáng)制線程終止的方法了!
由于stop方法可以讓一個(gè)線程A終止掉另一個(gè)線程B
被終止的線程B會(huì)立即釋放鎖,這可能會(huì)讓對(duì)象處于不一致的狀態(tài)。
線程A也不知道線程B什么時(shí)候能夠被終止掉,萬(wàn)一線程B還處理運(yùn)行計(jì)算階段,線程A調(diào)用stop方法將線程B終止,那就很無(wú)辜了~
總而言之,Stop方法太暴力了,不安全,所以被設(shè)置過(guò)時(shí)了。
我們一般使用的是interrupt來(lái)請(qǐng)求終止線程~
要注意的是:interrupt不會(huì)真正停止一個(gè)線程,它僅僅是給這個(gè)線程發(fā)了一個(gè)信號(hào)告訴它,它應(yīng)該要結(jié)束了(明白這一點(diǎn)非常重要!)
也就是說(shuō):Java設(shè)計(jì)者實(shí)際上是想線程自己來(lái)終止,通過(guò)上面的信號(hào),就可以判斷處理什么業(yè)務(wù)了。
具體到底中斷還是繼續(xù)運(yùn)行,應(yīng)該由被通知的線程自己處理
Thread t1 = new Thread( new Runnable(){ public void run(){ // 若未發(fā)生中斷,就正常執(zhí)行任務(wù) while(!Thread.currentThread.isInterrupted()){ // 正常任務(wù)代碼…… } // 中斷的處理代碼…… doSomething(); } } ).start();
再次說(shuō)明:調(diào)用interrupt()并不是要真正終止掉當(dāng)前線程,僅僅是設(shè)置了一個(gè)中斷標(biāo)志。這個(gè)中斷標(biāo)志可以給我們用來(lái)判斷什么時(shí)候該干什么活!什么時(shí)候中斷由我們自己來(lái)決定,這樣就可以安全地終止線程了!
我們來(lái)看看源碼是怎么講的吧:
再來(lái)看看剛才說(shuō)拋出的異常是什么東東吧:
所以說(shuō):interrupt方法壓根是不會(huì)對(duì)線程的狀態(tài)造成影響的,它僅僅設(shè)置一個(gè)標(biāo)志位罷了
interrupt線程中斷還有另外兩個(gè)方法(檢查該線程是否被中斷):
靜態(tài)方法interrupted()-->會(huì)清除中斷標(biāo)志位
實(shí)例方法isInterrupted()-->不會(huì)清除中斷標(biāo)志位
上面還提到了,如果阻塞線程調(diào)用了interrupt()方法,那么會(huì)拋出異常,設(shè)置標(biāo)志位為false,同時(shí)該線程會(huì)退出阻塞的。我們來(lái)測(cè)試一波:
public class Main { /** * @param args */ public static void main(String[] args) { Main main = new Main(); // 創(chuàng)建線程并啟動(dòng) Thread t = new Thread(main.runnable); System.out.println("This is main "); t.start(); try { // 在 main線程睡個(gè)3秒鐘 Thread.sleep(3000); } catch (InterruptedException e) { System.out.println("In main"); e.printStackTrace(); } // 設(shè)置中斷 t.interrupt(); } Runnable runnable = () -> { int i = 0; try { while (i < 1000) { // 睡個(gè)半秒鐘我們?cè)賵?zhí)行 Thread.sleep(500); System.out.println(i++); } } catch (InterruptedException e) { // 判斷該阻塞線程是否還在 System.out.println(Thread.currentThread().isAlive()); // 判斷該線程的中斷標(biāo)志位狀態(tài) System.out.println(Thread.currentThread().isInterrupted()); System.out.println("In Runnable"); e.printStackTrace(); } }; }
結(jié)果:
接下來(lái)我們分析它的執(zhí)行流程是怎么樣的:
2018年4月18日20:32:15(哇,這個(gè)方法真的消耗了我非常長(zhǎng)的時(shí)間).....感謝@開(kāi)始de痕跡的指教~
該參考資料:
https://www.cnblogs.com/w-wfy/p/6414801.html
https://www.cnblogs.com/carmanloneliness/p/3516405.html
https://www.zhihu.com/question/41048032/answer/89478427
https://www.zhihu.com/question/41048032/answer/89431513
二、總結(jié)可以發(fā)現(xiàn)我們的圖是還沒(méi)有補(bǔ)全的~后續(xù)的文章講到同步的時(shí)候會(huì)繼續(xù)使用上面的圖的。在Thread中重要的還是那幾個(gè)可以切換線程狀態(tài)的方法,還有理解中斷的真正含義。
使用線程會(huì)導(dǎo)致我們數(shù)據(jù)不安全,甚至程序無(wú)法運(yùn)行的情況的,這些問(wèn)題都會(huì)再后面講解到的~
之前在學(xué)習(xí)操作系統(tǒng)的時(shí)候根據(jù)《計(jì)算機(jī)操作系統(tǒng)-湯小丹》這本書(shū)也做了一點(diǎn)點(diǎn)筆記,都是比較淺顯的知識(shí)點(diǎn)。或許對(duì)大家有幫助
操作系統(tǒng)第一篇【引論】
操作系統(tǒng)第二篇【進(jìn)程管理】
操作系統(tǒng)第三篇【線程】
操作系統(tǒng)第四篇【處理機(jī)調(diào)度】
操作系統(tǒng)第五篇【死鎖】
操作系統(tǒng)第六篇【存儲(chǔ)器管理】
操作系統(tǒng)第七篇【設(shè)備管理】
參考資料:
《Java核心技術(shù)卷一》
《Java并發(fā)編程實(shí)戰(zhàn)》
《計(jì)算機(jī)操作系統(tǒng)-湯小丹》
如果文章有錯(cuò)的地方歡迎指正,大家互相交流。習(xí)慣在微信看技術(shù)文章,想要獲取更多的Java資源的同學(xué),可以關(guān)注微信公眾號(hào):Java3y。為了大家方便,剛新建了一下qq群:742919422,大家也可以去交流交流。謝謝支持了!希望能多介紹給其他有需要的朋友
文章的目錄導(dǎo)航:
https://zhongfucheng.bitcron.com/post/shou-ji/wen-zhang-dao-hang
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/69124.html
Volley is an HTTP library that makes networking for Android apps easier and most importantly, faster. Volley是Google在2013年推出來(lái)的HTTP庫(kù),旨在幫助開(kāi)發(fā)者更快更簡(jiǎn)便的實(shí)現(xiàn)網(wǎng)絡(luò)請(qǐng)求。說(shuō)說(shuō)為什么要分析Volley的源碼吧,因?yàn)閂olley中線程的轉(zhuǎn)換時(shí)通過(guò) Thread 和 Ha...
摘要:系統(tǒng)級(jí)線程核心級(jí)線程由操作系統(tǒng)內(nèi)核進(jìn)行管理。值得注意的是多線程的存在,不是提高程序的執(zhí)行速度。實(shí)現(xiàn)多線程上面說(shuō)了一大堆基礎(chǔ),理解完的話。虛擬機(jī)的啟動(dòng)是單線程的還是多線程的是多線程的。 前言 之前花了一個(gè)星期回顧了Java集合: Collection總覽 List集合就這么簡(jiǎn)單【源碼剖析】 Map集合、散列表、紅黑樹(shù)介紹 HashMap就是這么簡(jiǎn)單【源碼剖析】 LinkedHashMa...
摘要:等到所有子線程都執(zhí)行完后即,會(huì)主調(diào)用線程,然后主調(diào)用線程就會(huì)從函數(shù)返回,繼續(xù)后余動(dòng)作。 原理剖析(第 005 篇)AQS工作原理分析 - 一、大致介紹 1、前面章節(jié)講解了一下CAS,簡(jiǎn)單講就是cmpxchg+lock的原子操作; 2、而在談到并發(fā)操作里面,我們不得不談到AQS,JDK的源碼里面好多并發(fā)的類都是通過(guò)Sync的內(nèi)部類繼承AQS而實(shí)現(xiàn)出五花八門的功能; 3、本章節(jié)就和大家分享...
閱讀 3303·2021-11-19 09:40
閱讀 3723·2021-11-16 11:52
閱讀 3061·2021-11-11 16:55
閱讀 3268·2019-08-30 15:55
閱讀 1267·2019-08-30 13:08
閱讀 1740·2019-08-29 17:03
閱讀 3110·2019-08-29 16:19
閱讀 2667·2019-08-29 13:43