線程不是進程
作為有一定開發(fā)經(jīng)驗的程序員來說,在 java 中實現(xiàn)多線程是一件很容易的事情,你只需要將你的類繼承 Thread 類或者實現(xiàn) Runnable 接口就可以。 其實線程完全可以理解為一個任務(wù)。 可以同時運行多個任務(wù)的程序,就成為多線程程序。
然而線程并非進程。 進程包括線程,每一個進程都擁有一套自己的變量,而線程間則共享這套變量。 從而帶來了很多風險,比如最典型的臟數(shù)據(jù)。這些以后會討論。
線程狀態(tài)
在 java 中,線程被定義成有 6 中狀態(tài):
NEW
至今尚未啟動的線程處于這種狀態(tài)。 即剛剛 new 出來的 Thread ,但是還未調(diào)用 start ()方法。
RUNNABLE
正在 Java 虛擬機中執(zhí)行的線程處于這種狀態(tài)。 該狀態(tài)是調(diào)用了 start() 方法后的狀態(tài),出于該狀態(tài)的線程不一定是正在運行的,他有線程調(diào)度器來決定是否運行。
BLOCKED
受阻塞并等待某個監(jiān)視器鎖的線程處于這種狀態(tài)。 阻塞與等待不同,阻塞通常是得不到所需要的資源而被迫停下來等待。
WAITING
無限期地等待另一個線程來執(zhí)行某一特定操作的線程處于這種狀態(tài)。
TIMED_WAITING
等待另一個線程來執(zhí)行取決于指定等待時間的操作的線程處于這種狀態(tài)。
TERMINATED
已退出的線程處于這種狀態(tài)。有兩種情況會讓線程退出,其一是 run 方法中的任務(wù)執(zhí)行完成,其二是線程執(zhí)行時出現(xiàn)異常。
java 的線程狀態(tài)只有如上 6 中,他們以 enum 形式被定義在 Thread.State 中。這里要說一下等待狀態(tài),有很多方式能夠讓線程進入等待狀態(tài),比如調(diào)用 join ()方法。
join()
對于這個方法,還是要特別的強調(diào)一下。在
api
中的解釋如下:
Blocks the current Thread (
Thread.currentThread()
) until the receiver finishes its execution and dies.
翻譯過來就是:阻塞當前線程,然后讓接受者完成任務(wù)之后,當前線程才開始繼續(xù)執(zhí)行任務(wù)。
但是如果接受者在被調(diào)用了 join 方法后,有被調(diào)用了 interrupt() 方法,則會拋出 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() 方法是將當前線程阻塞
interrupt() 與中斷線程
開發(fā)時常常需要用到中斷線程,在早期的 java 版本中,有 stop() 等方法用來控制線程生死,當時這些方法現(xiàn)在已經(jīng)廢棄,具體愿意以后會談,同時亦可以參考 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
當然, jdk 還是為我們提供了強化終止線程的方法。然而, interrupt 方法只是可以用來請求終止線程。當對一個線程調(diào)用 interrupt 方法之后,線程的中斷狀態(tài)將被置位。每一個線程都具有一個 中斷狀態(tài) ,他是一個 boolean 標志。在實現(xiàn)自己的線程時,應(yīng)該實時檢查該標志,以判斷線程是否被中斷。
可以通過 Thread.currentThread() 方法得到當前線程,然后通過 is isInterrupted() 方法,來查看中斷狀態(tài)。通常如下實現(xiàn):
while (!Thread.currentThread().isInterrupted() && 。。。 ) {}
如果你已經(jīng)運行了 ThreadDemo01 代碼,那么你會發(fā)現(xiàn),在 TA 類中如下代碼處:
- if ?(i?==? 10 )?{ ??
- ??
- ?????????????????????????????????????Thread.currentThread().interrupt(); ??
- ??
- ????????????????????????????}??
if (i == 10) { Thread.currentThread().interrupt(); }
?
?
?
?
將會拋出異常 java.lang.InterruptedException 。這個是由于在 TA 線程中調(diào)用了 interrupt 方法后,中斷狀態(tài)已經(jīng)置為,如果此時再調(diào)用 sleep 等阻塞方法后, 該線程不會休眠,想法,他將拋出中斷異常并且將中斷狀態(tài)清楚。 所以如下代碼是不會讓線程 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)用,將能終止線程 } } }
?
?
?
?
你可以自己試一試,運行如上代碼,不能中斷 TB 線程。但是如果在 sleep 之后調(diào)用 interrupt ,則會中斷線程。
interrupted() 與 isInterrupted ()
這兩個方法看上去很像,作用也相似可以通過下表來比較兩種異同。
? |
是否是 static |
返回值 |
不同 |
interrupted |
是 |
當前的中斷狀態(tài) |
調(diào)用后改變中斷狀態(tài) |
isInterrupted |
否 |
不改變 ? |
線程屬性 ---- 線程優(yōu)先級
?
談優(yōu)先級可能并不陌生,在 java 中,每一個線程都有一個優(yōu)先級。默認情況下, 一個線程的優(yōu)先級直接繼承自他的父類。 sun 將 java 的優(yōu)先級分成 10 級, 1 表示最小優(yōu)先級, 10 表示最高優(yōu)先級。同時 jdk 中還定義了 3 個常量 MIN_PRIORITY(1 級 ) 、 MAX_PRIORITY(10 級 ) 、 NORM_PRIORITY(5 級 ) 。
線程的優(yōu)先級是依賴與平臺的, windows 中有 7 個優(yōu)先級。而在 Linux 中, java 虛擬機將線程的優(yōu)先級忽略,即所有線程的優(yōu)先級都一樣。 所以在編寫程序是,盡量不要依賴于優(yōu)先級。
setPriority() 方法,顧名思義就是設(shè)置優(yōu)先級的。
yield ()
yield 的中文意思是:屈服。其實理解成讓步更加準確。調(diào)用該方法,將導(dǎo)致當前執(zhí)行線程出于讓步狀態(tài)。如果此時有其他線程一起來搶奪 cpu 資源,那么只要這個搶奪的線程的優(yōu)先級不低于調(diào)用線程。則搶奪線程將會被調(diào)用。
線程屬性 ---- 守護線程
守護線程的用途就是為其他線程提供服務(wù)。當被服務(wù)者死亡后,其也就沒有存在的價值,也就跟著去死了。設(shè)置守護線程很簡單:
setDaemon ( true )
只需一步,輕松搞定。在使用守護線程時需要記住,永遠不要去訪問固有資源,如文件、數(shù)據(jù)庫等。以為你不知道什么時候守護線程會結(jié)束。
可以參考 DeamonDemo :
?
?
- package ?cn.edu.heut.zcl; ??
- ??
- /** ?
- ?
- ?*?演示守護線程 ?
- ?
- ?*?@author?Legend ?
- ?
- ?* ?
- ?
- ?*/ ??
- ??
- public ? class ?DeamonDemo?{ ??
- ??
- ????????? ??
- ??
- ????????? public ? static ? void ?main(String[]?args){ ??
- ??
- ???????????????????DemonRunnable?dr?=? new ?DemonRunnable(); ??
- ??
- ???????????????????dr.setDaemon( true ); //設(shè)置為守護線程 ??
- ??
- ???????????????????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號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
