線程不是進(jìn)程
作為有一定開發(fā)經(jīng)驗(yàn)的程序員來說,在 java 中實(shí)現(xiàn)多線程是一件很容易的事情,你只需要將你的類繼承 Thread 類或者實(shí)現(xiàn) Runnable 接口就可以。 其實(shí)線程完全可以理解為一個(gè)任務(wù)。 可以同時(shí)運(yùn)行多個(gè)任務(wù)的程序,就成為多線程程序。
然而線程并非進(jìn)程。 進(jìn)程包括線程,每一個(gè)進(jìn)程都擁有一套自己的變量,而線程間則共享這套變量。 從而帶來了很多風(fēng)險(xiǎn),比如最典型的臟數(shù)據(jù)。這些以后會(huì)討論。
線程狀態(tài)
在 java 中,線程被定義成有 6 中狀態(tài):
NEW
至今尚未啟動(dòng)的線程處于這種狀態(tài)。 即剛剛 new 出來的 Thread ,但是還未調(diào)用 start ()方法。
RUNNABLE
正在 Java 虛擬機(jī)中執(zhí)行的線程處于這種狀態(tài)。 該狀態(tài)是調(diào)用了 start() 方法后的狀態(tài),出于該狀態(tài)的線程不一定是正在運(yùn)行的,他有線程調(diào)度器來決定是否運(yùn)行。
BLOCKED
受阻塞并等待某個(gè)監(jiān)視器鎖的線程處于這種狀態(tài)。 阻塞與等待不同,阻塞通常是得不到所需要的資源而被迫停下來等待。
WAITING
無限期地等待另一個(gè)線程來執(zhí)行某一特定操作的線程處于這種狀態(tài)。
TIMED_WAITING
等待另一個(gè)線程來執(zhí)行取決于指定等待時(shí)間的操作的線程處于這種狀態(tài)。
TERMINATED
已退出的線程處于這種狀態(tài)。有兩種情況會(huì)讓線程退出,其一是 run 方法中的任務(wù)執(zhí)行完成,其二是線程執(zhí)行時(shí)出現(xiàn)異常。
java 的線程狀態(tài)只有如上 6 中,他們以 enum 形式被定義在 Thread.State 中。這里要說一下等待狀態(tài),有很多方式能夠讓線程進(jìn)入等待狀態(tài),比如調(diào)用 join ()方法。
join()
對于這個(gè)方法,還是要特別的強(qiáng)調(diào)一下。在
api
中的解釋如下:
Blocks the current Thread (
Thread.currentThread()
) until the receiver finishes its execution and dies.
翻譯過來就是:阻塞當(dāng)前線程,然后讓接受者完成任務(wù)之后,當(dāng)前線程才開始繼續(xù)執(zhí)行任務(wù)。
但是如果接受者在被調(diào)用了 join 方法后,有被調(diào)用了 interrupt() 方法,則會(huì)拋出 java.lang.InterruptedException 異常。可以參考代碼 ThreadDemo01 。
?
- <STRONG> package ?cn.edu.heut.zcl; ??
- ??
- ? ??
- ??
- public ? class ?ThreadDemo01?{ ??
- ??
- ? ??
- ??
- ????????? public ? static ? void ?main(String[]?args)?{ ??
- ??
- ???????????????????TA?ta?=? new ?TA(); ??
- ??
- ???????????????????ta.start(); ??
- ??
- ??????????????????? try ?{ ??
- ??
- ????????????????????????????ta.join(); ??
- ??
- ???????????????????}? catch ?(InterruptedException?e)?{ ??
- ??
- ????????????????????????????e.printStackTrace(); ??
- ??
- ???????????????????} ??
- ??
- ??????????????????? int ?i?=? 0 ; ??
- ??
- ??????????????????? while ?((i++)?<? 10 )?{ ??
- ??
- ????????????????????????????System.out.println( "-------" ); ??
- ??
- ???????????????????????????? try ?{ ??
- ??
- ?????????????????????????????????????Thread.sleep( 100 ); ??
- ??
- ????????????????????????????}? catch ?(InterruptedException?e)?{ ??
- ??
- ?????????????????????????????????????e.printStackTrace(); ??
- ??
- ????????????????????????????} ??
- ??
- ???????????????????} ??
- ??
- ?????????} ??
- ??
- } ??
- ??
- class ?TA? extends ?Thread?{ ??
- ??
- ? ??
- ??
- ????????? @Override ??
- ??
- ????????? public ? void ?run()?{ ??
- ??
- ??????????????????? super .run(); ??
- ??
- ??????????????????? int ?i?=? 0 ; ??
- ??
- ??????????????????? while ?((i++)?<? 40 )?{ ??
- ??
- ????????????????????????????System.out.println( "---->A" ); ??
- ??
- ???????????????????????????? if ?(i?==? 10 )?{ ??
- ??
- ?????????????????????????????????????Thread.currentThread().interrupt(); ??
- ??
- ????????????????????????????} ??
- ??
- ??
- ???????????????????????????? try ?{ ??
- ??
- ?????????????????????????????????????Thread.sleep( 100 ); ??
- ??
- ????????????????????????????}? catch ?(InterruptedException?e)?{ ??
- ??
- ????????????????????????????????????? //?TODO?Auto-generated?catch?block ??
- ??
- ?????????????????????????????????????e.printStackTrace(); ??
- ??
- ????????????????????????????} ??
- ??
- ???????????????????} ??
- ??
- ?????????} ??
- ??
- } ??
- </STRONG>??
package cn.edu.heut.zcl; public class ThreadDemo01 { public static void main(String[] args) { TA ta = new TA(); ta.start(); try { ta.join(); } catch (InterruptedException e) { e.printStackTrace(); } int i = 0; while ((i++) < 10) { System.out.println("-------"); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } } class TA extends Thread { @Override public void run() { super.run(); int i = 0; while ((i++) < 40) { System.out.println("---->A"); if (i == 10) { Thread.currentThread().interrupt(); } try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
?
?
?
?
記住: join() 方法是將當(dāng)前線程阻塞
interrupt() 與中斷線程
開發(fā)時(shí)常常需要用到中斷線程,在早期的 java 版本中,有 stop() 等方法用來控制線程生死,當(dāng)時(shí)這些方法現(xiàn)在已經(jīng)廢棄,具體愿意以后會(huì)談,同時(shí)亦可以參考 sun 的一片文章《 Why Are Thread.stop, Thread.suspend, Thread.resume and Runtime.runFinalizersOnExit Deprecated? 》網(wǎng)址如下:
http://download.oracle.com/javase/1.5.0/docs/guide/misc/threadPrimitiveDeprecation.html
當(dāng)然, jdk 還是為我們提供了強(qiáng)化終止線程的方法。然而, interrupt 方法只是可以用來請求終止線程。當(dāng)對一個(gè)線程調(diào)用 interrupt 方法之后,線程的中斷狀態(tài)將被置位。每一個(gè)線程都具有一個(gè) 中斷狀態(tài) ,他是一個(gè) boolean 標(biāo)志。在實(shí)現(xiàn)自己的線程時(shí),應(yīng)該實(shí)時(shí)檢查該標(biāo)志,以判斷線程是否被中斷。
可以通過 Thread.currentThread() 方法得到當(dāng)前線程,然后通過 is isInterrupted() 方法,來查看中斷狀態(tài)。通常如下實(shí)現(xiàn):
while (!Thread.currentThread().isInterrupted() && 。。。 ) {}
如果你已經(jīng)運(yùn)行了 ThreadDemo01 代碼,那么你會(huì)發(fā)現(xiàn),在 TA 類中如下代碼處:
- if ?(i?==? 10 )?{ ??
- ??
- ?????????????????????????????????????Thread.currentThread().interrupt(); ??
- ??
- ????????????????????????????}??
if (i == 10) { Thread.currentThread().interrupt(); }
?
?
?
?
將會(huì)拋出異常 java.lang.InterruptedException 。這個(gè)是由于在 TA 線程中調(diào)用了 interrupt 方法后,中斷狀態(tài)已經(jīng)置為,如果此時(shí)再調(diào)用 sleep 等阻塞方法后, 該線程不會(huì)休眠,想法,他將拋出中斷異常并且將中斷狀態(tài)清楚。 所以如下代碼是不會(huì)讓線程 TB 停止。 CopyOfThreadDemo02
?
- package ?cn.edu.heut.zcl; ??
- ??
- ? ??
- ??
- public ? class ?CopyOfThreadDemo02?{ ??
- ??
- ? ??
- ??
- ????????? public ? static ? void ?main(String[]?args)?{ ??
- ??
- ???????????????????TB?ta?=? new ?TB(); ??
- ??
- ???????????????????ta.start(); ??
- ??
- ??????????????????? int ?i?=? 0 ; ??
- ??
- ??????????????????? while ?((i++)?<? 10 )?{ ??
- ??
- ????????????????????????????System.out.println( "-------" ); ??
- ??
- ???????????????????????????? try ?{ ??
- ??
- ?????????????????????????????????????Thread.sleep( 100 ); ??
- ??
- ????????????????????????????}? catch ?(InterruptedException?e)?{ ??
- ??
- ?????????????????????????????????????e.printStackTrace(); ??
- ??
- ????????????????????????????} ??
- ??
- ???????????????????} ??
- ??
- ?????????} ??
- ??
- } ??
- ??
- ? ??
- ??
- class ?TB? extends ?Thread?{ ??
- ??
- ? ??
- ??
- ????????? @Override ??
- ??
- ????????? public ? void ?run()?{ ??
- ??
- ??????????????????? super .run(); ??
- ??
- ??????????????????? int ?i?=? 0 ; ??
- ??
- ??????????????????? while ?(!Thread.currentThread().isInterrupted()?&&?(i++)?<? 40 )?{ ??
- ??
- ????????????????????????????System.out.println( "---->A" ); ??
- ??
- ???????????????????????????? if (i?==? 4 )?Thread.currentThread().interrupt(); //在sleep之前調(diào)用,將不能終止線程 ??
- ??
- ???????????????????????????? try ?{ ??
- ??
- ?????????????????????????????????????Thread.sleep( 100 ); ??
- ??
- ????????????????????????????}? catch ?(InterruptedException?e)?{ ??
- ??
- ????????????????????????????????????? //?TODO?Auto-generated?catch?block ??
- ??
- ?????????????????????????????????????e.printStackTrace(); ??
- ??
- ????????????????????????????} ??
- ??
- ???????????????????????????? //if(i?==?4)?Thread.currentThread().interrupt();//在sleep之后調(diào)用,將能終止線程 ??
- ??
- ???????????????????} ??
- ??
- ?????????} ??
- ??
- }??
package cn.edu.heut.zcl; public class CopyOfThreadDemo02 { public static void main(String[] args) { TB ta = new TB(); ta.start(); int i = 0; while ((i++) < 10) { System.out.println("-------"); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } } class TB extends Thread { @Override public void run() { super.run(); int i = 0; while (!Thread.currentThread().isInterrupted() && (i++) < 40) { System.out.println("---->A"); if(i == 4) Thread.currentThread().interrupt();//在sleep之前調(diào)用,將不能終止線程 try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } //if(i == 4) Thread.currentThread().interrupt();//在sleep之后調(diào)用,將能終止線程 } } }
?
?
?
?
你可以自己試一試,運(yùn)行如上代碼,不能中斷 TB 線程。但是如果在 sleep 之后調(diào)用 interrupt ,則會(huì)中斷線程。
interrupted() 與 isInterrupted ()
這兩個(gè)方法看上去很像,作用也相似可以通過下表來比較兩種異同。
? |
是否是 static |
返回值 |
不同 |
interrupted |
是 |
當(dāng)前的中斷狀態(tài) |
調(diào)用后改變中斷狀態(tài) |
isInterrupted |
否 |
不改變 ? |
線程屬性 ---- 線程優(yōu)先級(jí)
?
談優(yōu)先級(jí)可能并不陌生,在 java 中,每一個(gè)線程都有一個(gè)優(yōu)先級(jí)。默認(rèn)情況下, 一個(gè)線程的優(yōu)先級(jí)直接繼承自他的父類。 sun 將 java 的優(yōu)先級(jí)分成 10 級(jí), 1 表示最小優(yōu)先級(jí), 10 表示最高優(yōu)先級(jí)。同時(shí) jdk 中還定義了 3 個(gè)常量 MIN_PRIORITY(1 級(jí) ) 、 MAX_PRIORITY(10 級(jí) ) 、 NORM_PRIORITY(5 級(jí) ) 。
線程的優(yōu)先級(jí)是依賴與平臺(tái)的, windows 中有 7 個(gè)優(yōu)先級(jí)。而在 Linux 中, java 虛擬機(jī)將線程的優(yōu)先級(jí)忽略,即所有線程的優(yōu)先級(jí)都一樣。 所以在編寫程序是,盡量不要依賴于優(yōu)先級(jí)。
setPriority() 方法,顧名思義就是設(shè)置優(yōu)先級(jí)的。
yield ()
yield 的中文意思是:屈服。其實(shí)理解成讓步更加準(zhǔn)確。調(diào)用該方法,將導(dǎo)致當(dāng)前執(zhí)行線程出于讓步狀態(tài)。如果此時(shí)有其他線程一起來搶奪 cpu 資源,那么只要這個(gè)搶奪的線程的優(yōu)先級(jí)不低于調(diào)用線程。則搶奪線程將會(huì)被調(diào)用。
線程屬性 ---- 守護(hù)線程
守護(hù)線程的用途就是為其他線程提供服務(wù)。當(dāng)被服務(wù)者死亡后,其也就沒有存在的價(jià)值,也就跟著去死了。設(shè)置守護(hù)線程很簡單:
setDaemon ( true )
只需一步,輕松搞定。在使用守護(hù)線程時(shí)需要記住,永遠(yuǎn)不要去訪問固有資源,如文件、數(shù)據(jù)庫等。以為你不知道什么時(shí)候守護(hù)線程會(huì)結(jié)束。
可以參考 DeamonDemo :
?
?
- package ?cn.edu.heut.zcl; ??
- ??
- /** ?
- ?
- ?*?演示守護(hù)線程 ?
- ?
- ?*?@author?Legend ?
- ?
- ?* ?
- ?
- ?*/ ??
- ??
- public ? class ?DeamonDemo?{ ??
- ??
- ????????? ??
- ??
- ????????? public ? static ? void ?main(String[]?args){ ??
- ??
- ???????????????????DemonRunnable?dr?=? new ?DemonRunnable(); ??
- ??
- ???????????????????dr.setDaemon( true ); //設(shè)置為守護(hù)線程 ??
- ??
- ???????????????????dr.start(); ??
- ??
- ??????????????????? int ?i?=? 0 ?; ??
- ??
- ??????????????????? while ((i++)< 10 ){ ??
- ??
- ???????????????????????????? try ?{ ??
- ??
- ?????????????????????????????????????Thread.sleep( 500 ); ??
- ??
- ?????????????????????????????????????System.out.println(i); ??
- ??
- ????????????????????????????}? catch ?(InterruptedException?e)?{ ??
- ??
- ?????????????????????????????????????e.printStackTrace(); ??
- ??
- ????????????????????????????} ??
- ??
- ???????????????????} ??
- ??
- ?????????} ??
- ??
- ????????? ??
- ??
- ????????? private ? static ? class ?DemonRunnable? extends ?Thread{ ??
- ??
- ??????????????????? @Override ??
- ??
- ??????????????????? public ? void ?run()?{ ??
- ??
- ???????????????????????????? super .run(); ??
- ??
- ???????????????????????????? while ( true ){ ??
- ??
- ?????????????????????????????????????System.out.println( "------" ); ??
- ??
- ????????????????????????????????????? try ?{ ??
- ??
- ???????????????????????????????????????????????Thread.sleep( 100 ); ??
- ??
- ?????????????????????????????????????}? catch ?(InterruptedException?e)?{ ??
- ??
- ???????????????????????????????????????????????e.printStackTrace(); ??
- ??
- ?????????????????????????????????????} ??
- ??
- ????????????????????????????} ??
- ??
- ???????????????????} ??
- ??
- ?????????} ??
- ??
- }??
?
?
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
