Java線程的啟動與中止

一窒百、線程與進(jìn)程的關(guān)系

關(guān)于進(jìn)程與線程撮胧,百度百科上是這樣描述的:

進(jìn)程(Process)?是計算機(jī)中的程序關(guān)于某數(shù)據(jù)集合上的一次運行活動是钥,是系統(tǒng)進(jìn)行資源分配和調(diào)度的基本單位僻肖,是操作系統(tǒng)結(jié)構(gòu)的基礎(chǔ)肖爵。 在當(dāng)代面向線程設(shè)計的計算機(jī)結(jié)構(gòu)中,進(jìn)程是線程的容器臀脏。程序是指令劝堪、數(shù)據(jù)及其組織形式的描述冀自,進(jìn)程是程序的實體。是計算機(jī)中的程序關(guān)于某數(shù)據(jù)集合上的一次運行活動秒啦,是系統(tǒng)進(jìn)行資源分配和調(diào)度的基本單位熬粗,是操作系統(tǒng)結(jié)構(gòu)的基礎(chǔ)。程序是指令余境、數(shù)據(jù)及其組織形式的描述驻呐,進(jìn)程是程序的實體插掂。

線程(thread)?是操作系統(tǒng)能夠進(jìn)行運算調(diào)度的最小單位贝咙。它被包含在進(jìn)程之中逆粹,是進(jìn)程中的實際運作單位衙荐。一條線程指的是進(jìn)程中一個單一順序的控制流,一個進(jìn)程中可以并發(fā)多個線程蛉腌,每條線程并行執(zhí)行不同的任務(wù)偿荷。

簡單的總結(jié)一下檐春,就變成了下面的結(jié)果:

進(jìn)程(Process): 程序運行資源分配的最小單位顽聂,進(jìn)程內(nèi)部有多個線程肥惭,會共享這個進(jìn)程的資源。

線程(thread)?: CPU調(diào)度的最小單位紊搪,必須依賴進(jìn)程而存在蜜葱。

也就是說?線程進(jìn)程的關(guān)系,就像玄幻小說中蟲族的母體和子體一樣嗦明,子體離開了母體便不能存活笼沥。線程亦是如此蚪燕,必須依賴于進(jìn)程而存在娶牌。

二、Java線程的啟動方式

關(guān)于Java的線程馆纳,我們首當(dāng)其沖的會想到j(luò)ava.lang.Thread類诗良,這是一種最簡單的創(chuàng)建線程的方式,我們只需要通過繼承Thread類就可以實現(xiàn):

/** *@authorcai * 通過繼承Thread類的方式 */privatestaticclassUserThreadextendsThread{/**

? ? * 重寫? Thread 類的? run() 方法

? ? */@Overridepublicvoidrun(){? ? ? ? System.out.println("this is a thread for extends Thread");? ? }}

這里鲁驶,我們重寫了Thread類中的run()方法鉴裹,并打印一條語句來表示線程的啟動方式,現(xiàn)在我們來測試一下:

publicstaticvoidmain(String[] args){// 繼承Thread類的方式Thread thread =newUserThread();? ? thread.start();}

控制臺的打印結(jié)果:

thisisa threadforextendsThread

從打印結(jié)果可以看出钥弯,我們的線程正常的啟動径荔,中間沒有出現(xiàn)意外。除了這種方式之外脆霎,JDK內(nèi)部又給我們提供了一個接口類:java.lang.Runnable总处,同樣,我們也可以通過實現(xiàn)該接口睛蛛,重寫run()方法來啟動一個新的線程:

/** *@authorcai * 通過實現(xiàn)Runnable接口的方式 */privatestaticclassUserRunnableimplementsRunnable{/**

? ? * 重寫? Runnable 類的? run() 方法

? ? */@Overridepublicvoidrun(){? ? ? ? System.out.println("this is a thread for implements Runnable");? ? }}

這里我們同樣打印一句話來表示此線程的啟動方式鹦马,現(xiàn)在來測試一下:

publicstaticvoidmain(String[] args)throws{// 實現(xiàn)Runnable接口的方式// 這里注意:所有線程的啟動胧谈,都必須通過調(diào)用Thread類中start()方法來實現(xiàn)Runnable runnable =newUserRunnable();newThread(runnable).start();}

相信上面的代碼,小伙伴們都能看懂(多注意一下第二行的注釋荸频,這是重點)菱肖,現(xiàn)在來看看控制臺的打印結(jié)果:

thisisa threadforimplementsRunnable

同理,這里的線程也正常的啟動了旭从。但看到這里稳强,小伙伴們可能就會產(chǎn)生疑問,為什么JDK要多此一舉和悦,提供了一種Thread類后键袱,為什么還要提供Runnable接口類呢?

在這里給有這個疑惑的小伙伴們答疑下:

因為Java是單繼承摹闽,只能繼承一個類蹄咖,不能繼承多個類。而在我們某些實際的業(yè)務(wù)中付鹿,我們可能需要繼承一個類來處理邏輯業(yè)務(wù)澜汤,那么就不能再繼承Thread類來處理線程相關(guān)的操作了。所以JDK又為我們提供了一個實現(xiàn)Runnable接口的方式舵匾,而且在Java中俊抵,一個類是可以實現(xiàn)多個接口的,這樣我們在使用第二種方式處理線程就不會有顧忌了坐梯。(這里比較有意思的是:Thread類實現(xiàn)了Runnable接口徽诲,有興趣的小伙伴可以去看一下源碼。)

那么除了上面的兩種方式之外吵血,Java是否提供了第三種方式呢谎替?答案是肯定的,從JDK1.5開始蹋辅,JDK為我們提供了一個新的接口類:java.util.concurrent.Callable钱贯,我們可以通過實現(xiàn)這個接口來啟動一個新得線程,而這種方式與實現(xiàn)Runnable接口來啟動線程所不同的是侦另,它會帶有一個返回值秩命,我們來看一下代碼:

/** *@authorcai * 通過實現(xiàn)Callable接口的方式 * 帶返回值 */privatestaticclassUserCallableimplementsCallable{/**? ? * 重寫? Callable 類的? run() 方法? ? *@return*@throwsException? ? */@OverridepublicStringcall()throwsException{return"this is a thread for implements Callable(return String).";? ? }}

測試一下:


<html>

<head></head>

<body>

? publicstaticvoidmain(String[] args)throwsExecutionException, InterruptedException{// 實現(xiàn)Callable接口的方式 帶返回值UserCallable callable =newUserCallable(); FutureTask future =newFutureTask(callable);newThread(future).start(); System.out.println(future.get());}

</body>

</html>


我們這里將返回值打印一下:

thisisa threadforimplementsCallable(returnString).

可以看出,我們的線程正常的啟動褒傅,沒有問題弃锐。

那么看了以上三種Java線程的啟動方式,相信肯定有很多小伙伴會好奇殿托,如果我要中止一個線程霹菊,我需要怎么做呢?讓我們來一起看看吧碌尔。

三浇辜、Java線程的中止

怎樣讓一個正在運行的線程安全的停止工作呢券敌?這里有兩種方法:

1、線程自然的終止:程序正常的執(zhí)行完或者拋出未處理的異常柳洋。

程序正常的執(zhí)行完就不必再說待诅,以上的代碼都屬于此類,我們來看一看拋出未處理異常的情況熊镣,這里我們將上述實現(xiàn)Runnable接口來啟動線程的代碼修改一下:

/** *@authorcai * 通過實現(xiàn)Runnable接口的方式 */privatestaticclassUserRunnableimplementsRunnable{/**

? ? * 重寫? Runnable 類的? run() 方法

? ? */@Overridepublicvoidrun(){// 重點加了這樣的一行代碼inti =10/0;? ? ? ? System.out.println("this is a thread for implements Runnable");? ? }}

這里我們加了一行代碼卑雁,小伙伴們應(yīng)該都可以看懂,這行代碼是必定會拋出異常的绪囱,但我們又沒有對異常進(jìn)行處理测蹲,現(xiàn)在來看一下控制臺的打印結(jié)果:

Exceptioninthread"Thread-0"java.lang.ArithmeticException:/ by zeroat com.cai.thread.create.NewThread$UserRunnable.run(NewThread.java:39)at java.lang.Thread.run(Thread.java:748)

從結(jié)果可以看出,程序運行到了int i = 10 / 0這里就停止了鬼吵,并沒有打印出下一行的結(jié)果扣甲,由此可見,線程到了這里便停止了齿椅,沒有再走下去琉挖。

2、調(diào)用JDK為我們提供的一系列方法

stop()涣脚,resume(),suspend(),interrupt(),isInterrupted(),interrupted()這些方法都是JDK為我們提供的示辈,但是``stop(),resume(),suspend()`已經(jīng)不建議使用了遣蚀,原因如下:

stop()?: 會導(dǎo)致線程不會正常的釋放資源矾麻,“惡意”的中斷當(dāng)前正在運行的線程,不管線程的邏輯是否完整芭梯。

suspend()與resume()?: 極易造成公共的同步對象的獨占险耀,使得其他線程無法訪問公共同步對象,產(chǎn)生死鎖粥帚。(這個例子以后在講線程鎖的時候會解釋胰耗。)

我們先來看一下調(diào)用stop()的例子:


<html>

<head></head>

<body>

? /** *@authorcai * 調(diào)用 stop() 方法的例子 */privatestaticclassUserRunnableimplementsRunnable{@Overridepublicvoidrun(){try{// 讓此線程休眠1秒鐘Thread.sleep(1000); }catch(Exception e){// 異常 捕獲處理}// 此處不會運行,控制臺不會打印// 若實際開發(fā)中芒涡,這里要處理一個很重要的業(yè)務(wù)邏輯,那么這里就會有很大的問題卖漫。// 所以不建議使用System.out.println(&quot;代碼到此處不會運行&quot;); }}publicstaticvoidmain(String[] args)throwsInterruptedException{ Runnable runnable =newUserRunnable(); Thread thread =newThread(runnable); thread.start();// 強(qiáng)行中止線程// 從這里可以看出费尽,JDK已經(jīng)不建議使用stop()方法了,添加了@Deprecated注解thread.stop();}

</body>

</html>


我這里將測試代碼也一并貼了上去羊始,可以在代碼的注釋中得到相關(guān)的結(jié)果旱幼。講完這些,我們來看看剩下的三個方法:interrupt(),isInterrupted(),interrupted()

interrupt():調(diào)用此方法會中斷一個線程突委,但并不是強(qiáng)行關(guān)閉這個線程柏卤,只是先給這個線程打個招呼冬三,同事將線程的中斷標(biāo)志位設(shè)置為true,線程是否中斷缘缚,由線程本身決定勾笆。

isInterrupted():判斷當(dāng)前的線程是否處于中斷狀態(tài)(返回true或者false)。

interrupted():靜態(tài)方法桥滨,判斷當(dāng)前的線程是否處于中斷狀態(tài)窝爪,同時將中斷的標(biāo)志位設(shè)置為false。

注意:如果方法中拋出了InterruptedException異常齐媒,那么線程的中斷標(biāo)志位會被復(fù)位成false蒲每,如果確實需要中斷線程的操作,我們需要在catch語句中再次調(diào)用interrupt()方法喻括。

解釋完了邀杏,直接上代碼吧:


<html>

<head></head>

<body>

? /** *@authorcai * 調(diào)用 interrupt(),isInterrupted(),interrupted() 方法的例子 */privatestaticclassUserThreadextendsThread{// 給線程一個名字,創(chuàng)建對象時賦值publicUserThread(String threadName){super(threadName); }@Overridepublicvoidrun(){// 獲得線程的名字String threadName = Thread.currentThread().getName();try{// @2System.out.println(threadName+&quot; flag is &quot;+ isInterrupted());// 休眠一秒鐘 需要捕獲異常 InterruptedException @3Thread.sleep(1000); }catch(InterruptedException e){// 打印一下 isInterrupted() 的狀態(tài) @4System.out.println(threadName+&quot; catch interrput flag is &quot;+ isInterrupted());// 調(diào)用 interrupt() 方法 中斷線程操作 @5interrupt(); }// 打印線程的名字 @6System.out.println(threadName+&quot; interrput flag is &quot;+ interrupted());// @7System.out.println(threadName+&quot; interrput flag is &quot;+ isInterrupted()); }}publicstaticvoidmain(String[] args)throwsInterruptedException{// interrupt(),isInterrupted(),interrupted() 演示Thread thread =newUserThread(&quot;caiThread&quot;); thread.start();// @1thread.interrupt();}

</body>

</html>


這里為了方便解釋唬血,我分了步驟:

1淮阐、@1 的位置調(diào)用的interrupt()方法,所以這里的標(biāo)志位是true刁品,所以 @2 的位置打印結(jié)果為true泣特。

2、@3 位置的sleep方法會拋出InterruptedException異常挑随,我這里捕獲了状您,在看之前的理論,拋出此異常兜挨,標(biāo)志位會重置為false膏孟,所以@4 這里的打印結(jié)果為false。

3拌汇、@5 位置再次調(diào)用了interrupt()柒桑,又把標(biāo)志位改為了false,所以 @6 這里打印的結(jié)果為true噪舀,但是這里注意的是魁淳,@6 調(diào)用了interrupted()這個靜態(tài)方法,所以標(biāo)志位又變?yōu)榱薴alse与倡,所以@7 打印的結(jié)果為false界逛。

控制臺打印結(jié)果:

caiThreadcatchflagistruecaiThreadcatchinterrput flagisfalsecaiThread interrput flagistruecaiThread interrput flagisfalse

小伙伴們可以通過對比結(jié)果、代碼和解釋一起看纺座,相信還是很容易明白的息拜。

對線程的了解再多一點點

Java線程總歸下來有五種狀態(tài):

新建、就緒、阻塞少欺、運行喳瓣、死亡

而這里對應(yīng)的方法卻有很多種,具體的關(guān)系赞别,我這里準(zhǔn)備了一張圖:

這張圖上面的各種方法我都會在下次的文章中分享畏陕,這次的分享就到這里,希望大家能夠喜歡氯庆。

最后

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蹭秋,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子堤撵,更是在濱河造成了極大的恐慌仁讨,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,576評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件实昨,死亡現(xiàn)場離奇詭異洞豁,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)荒给,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評論 3 399
  • 文/潘曉璐 我一進(jìn)店門丈挟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人志电,你說我怎么就攤上這事曙咽。” “怎么了挑辆?”我有些...
    開封第一講書人閱讀 168,017評論 0 360
  • 文/不壞的土叔 我叫張陵例朱,是天一觀的道長。 經(jīng)常有香客問我鱼蝉,道長洒嗤,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,626評論 1 296
  • 正文 為了忘掉前任魁亦,我火速辦了婚禮渔隶,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘洁奈。我一直安慰自己间唉,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,625評論 6 397
  • 文/花漫 我一把揭開白布睬魂。 她就那樣靜靜地躺著终吼,像睡著了一般。 火紅的嫁衣襯著肌膚如雪氯哮。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,255評論 1 308
  • 那天,我揣著相機(jī)與錄音喉钢,去河邊找鬼姆打。 笑死,一個胖子當(dāng)著我的面吹牛肠虽,可吹牛的內(nèi)容都是我干的幔戏。 我是一名探鬼主播,決...
    沈念sama閱讀 40,825評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼税课,長吁一口氣:“原來是場噩夢啊……” “哼闲延!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起韩玩,我...
    開封第一講書人閱讀 39,729評論 0 276
  • 序言:老撾萬榮一對情侶失蹤垒玲,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后找颓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體合愈,經(jīng)...
    沈念sama閱讀 46,271評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,363評論 3 340
  • 正文 我和宋清朗相戀三年击狮,在試婚紗的時候發(fā)現(xiàn)自己被綠了佛析。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,498評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡彪蓬,死狀恐怖寸莫,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情档冬,我是刑警寧澤膘茎,帶...
    沈念sama閱讀 36,183評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站捣郊,受9級特大地震影響辽狈,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜呛牲,卻給世界環(huán)境...
    茶點故事閱讀 41,867評論 3 333
  • 文/蒙蒙 一刮萌、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧娘扩,春花似錦着茸、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,338評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至灰殴,卻和暖如春敬特,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,458評論 1 272
  • 我被黑心中介騙來泰國打工伟阔, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留辣之,地道東北人。 一個月前我還...
    沈念sama閱讀 48,906評論 3 376
  • 正文 我出身青樓皱炉,卻偏偏與公主長得像怀估,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子合搅,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,507評論 2 359