多線程編程一直是程序員比較頭痛和心虛的地方,因為線程執(zhí)行順序的不可預(yù)知性和調(diào)試時候的困難,讓不少人在面對多線程的情況下選擇了逃避,采用單線程的方式,其實只要我們對線程有了明確的認識,再加上Java內(nèi)置的對多線程的天然支持,多線程編程不再是一道難以逾越的鴻溝。 1、新建狀態(tài)(New):
目錄:
【一】進程、線程、并發(fā)執(zhí)行
【二】JVM與多線程
【三】Java語言對多線程的支持
【四】線程的狀態(tài)切換
【五】Java中線程的調(diào)度API
【六】參考文章
【一】進程、線程、并發(fā)執(zhí)行
關(guān)于進程、線程、并發(fā)執(zhí)行的概念,我們先來看下面的一段話:
“一般來說,當運行一個應(yīng)用程序的時候,就啟動了一個進程,當然有些會啟動多個進程。啟動進程的時候,操作系統(tǒng)會為進程分配資源,其中最主要的資源是內(nèi)存空間,因為程序是在內(nèi)存中運行的。
在進程中,有些程序流程塊是可以亂序執(zhí)行的,并且這個代碼塊可以同時被多次執(zhí)行。實際上,這樣的代碼塊就是線程體。線程是進程中亂序執(zhí)行的代碼流程。當多個線程同時運行的時候,這樣的執(zhí)行模式成為并發(fā)執(zhí)行。”
上面這段話引自51CTO網(wǎng)站“熔巖”的博客一篇文章《Java多線程編程總結(jié)》,讀者可參考本文獲得更詳細的知識。
下面我以一個日常生活中簡單的例子來說明進程和線程之間的區(qū)別和聯(lián)系:
這副圖是一個雙向多車道的道路圖,假如我們把整條道路看成是一個“進程”的話,那么圖中由白色虛線分隔開來的各個車道就是進程中的各個“線程”了。
①這些線程(車道)共享了進程(道路)的公共資源(土地資源)。
②這些線程(車道)必須依賴于進程(道路),也就是說,線程不能脫離于進程而存在(就像離開了道路,車道也就沒有意義了)。
③這些線程(車道)之間可以并發(fā)執(zhí)行(各個車道你走你的,我走我的),也可以互相同步(某些車道在交通燈亮時禁止繼續(xù)前行或轉(zhuǎn)彎,必須等待其它車道的車輛通行完畢)。
④這些線程(車道)之間依靠代碼邏輯(交通燈)來控制運行,一旦代碼邏輯控制有誤(死鎖,多個線程同時競爭唯一資源),那么線程將陷入混亂,無序之中。
⑤這些線程(車道)之間誰先運行是未知的,只有在線程剛好被分配到CPU時間片(交通燈變化)的那一刻才能知道
【二】JVM與多線程
Java編寫的程序都運行在在Java虛擬機(JVM)中,在JVM的內(nèi)部,程序的多任務(wù)是通過線程來實現(xiàn)的。
每用java命令啟動一個java應(yīng)用程序,就會啟動一個JVM進程。在同一個JVM進程中,有且只有一個進程,就是它自己。在這個JVM環(huán)境中,所有程序代碼的運行都是以線程來運行的。JVM找到程序程序的入口點main(),然后運行main()方法,這樣就產(chǎn)生了一個線程,這個線程稱之為主線程。當main方法結(jié)束后,主線程運行完成。JVM進程也隨即退出。
操作系統(tǒng)將進程線程進行管理,輪流(沒有固定的順序)分配每個進程很短的一段時間(不一定是均分),然后在每個進程內(nèi)部,程序代碼自己處理該進程內(nèi)部線程的時間分配,多個線程之間相互的切換去執(zhí)行,這個切換時間也是非常短的
【三】Java語言對多線程的支持
Java語言對多線程的支持通過類Thread和接口Runnable來實現(xiàn)。這里就不多說了,讀者可以參考《Java多線程編程總結(jié)》這篇文章得到更多的信息。這里重點強調(diào)兩個地方:
// 主線程其它代碼段
ThreadClass subThread = new ThreadClass();
subThread.start();
// 主線程其它代碼段
subThread.sleep(1000);
有人認為以下的代碼在調(diào)用start()方法后,肯定是先啟動子線程,然后主線程繼續(xù)執(zhí)行。在調(diào)用sleep()方法后CPU什么都不做,就在那里等待休眠的時間結(jié)束。實際上這種理解是錯誤的。因為:
①start()方法的調(diào)用后并不是立即執(zhí)行多線程代碼,而是使得該線程變?yōu)榭蛇\行態(tài)(Runnable),什么時候運行是由操作系統(tǒng)決定的。
②Thread.sleep()方法調(diào)用目的是不讓當前線程獨自霸占該進程所獲取的CPU資源,以留出一定時間給其他線程執(zhí)行的機會(也就是靠內(nèi)部自己協(xié)調(diào))。
【四】線程的狀態(tài)切換
前面我們提到,由于線程何時執(zhí)行是未知的,只有在CPU為線程分配到時間片時,線程才能真正執(zhí)行。在線程執(zhí)行的過程中,由可能會因為各種各樣的原因的原因而暫停(就像前面所舉的例子一樣:汽車只有在交通燈變綠的時候才能夠通行,而且在行駛的過程中可能會出現(xiàn)塞車,等待其它車輛通行或轉(zhuǎn)彎的狀況)。
這樣線程就有了“狀態(tài)”的概念,下面這副圖,是從《Java多線程編程總結(jié)》一文中摘錄出來的。很好的反映了線程在不同情況下的狀態(tài)變化
新創(chuàng)建了一個線程對象。
2、就緒狀態(tài)(Runnable):
線程對象創(chuàng)建后,其他線程調(diào)用了該對象的start()方法。該狀態(tài)的線程位于可運行線程池中,變得可運行,等待獲取CPU的使用權(quán)。
3、運行狀態(tài)(Running):
就緒狀態(tài)的線程獲取了CPU,執(zhí)行程序代碼。
4、阻塞狀態(tài)(Blocked):
阻塞狀態(tài)是線程因為某種原因放棄CPU使用權(quán),暫時停止運行。直到線程進入就緒狀態(tài),才有機會轉(zhuǎn)到運行狀態(tài)。阻塞的情況分三種:
①等待阻塞:運行的線程執(zhí)行wait()方法,JVM會把該線程放入等待池中。
②同步阻塞:運行的線程在獲取對象的同步鎖時,若該同步鎖被別的線程占用,則JVM把該線程放入鎖池
③其他阻塞:運行的線程執(zhí)行sleep()或join()方法,或者發(fā)出了I/O請求時,JVM會把該線程置為阻塞狀態(tài)。當sleep()狀態(tài)超時、join()等待線程終止或者超時、或者I/O處理完畢時,線程重新轉(zhuǎn)入就緒狀態(tài)。
5、死亡狀態(tài)(Dead):
線程執(zhí)行完了或者因異常退出了run()方法,該線程結(jié)束生命周期。
【五】Java中線程的調(diào)度API
Java中關(guān)于線程調(diào)度的API最主要的有下面幾個:
①線程睡眠:Thread.sleep(long millis)方法
②線程等待:Object類中的wait()方法
③線程讓步:Thread.yield() 方法
④線程加入:join()方法
⑤線程喚醒:Object類中的notify()方法
關(guān)于這幾個方法的詳細應(yīng)用,可以參考SUN的API,及《Java多線程編程總結(jié)》一文第七部分“線程的調(diào)度”。這里我重點總結(jié)一下這幾個方法的區(qū)別和使用:
備注:sleep方法與wait方法的區(qū)別:
①sleep方法是靜態(tài)方法,wait方法是非靜態(tài)方法。
②sleep方法在時間到后會自己“醒來”,但wait不能,必須由其它線程通過notify(All)方法讓它“醒來”
③sleep方法通常用在不需要等待資源情況下的阻塞,像等待線程、數(shù)據(jù)庫連接的情況一般用wait
備注:sleep/wait與yeld方法的區(qū)別:
①調(diào)用sleep或wait方法后,線程即進入block狀態(tài),而調(diào)用yeld方法后,線程進入runnable狀態(tài)
備注:wait與join方法的區(qū)別:
②wait方法必須由其它線程來解鎖,而join方法不需要,只要被等待線程執(zhí)行完畢,當前線程自動變?yōu)榫途w
③join方法的一個用途就是讓子線程在完成業(yè)務(wù)邏輯執(zhí)行之前,主線程一直等待直到所有子線程執(zhí)行完畢。
【六】參考文章
www.51cto.com網(wǎng)站 熔巖的博文《Java多線程編程總結(jié)》
-------------------------------------------------------------
生活就像打牌,不是要抓一手好牌,而是要盡力打好一手爛牌。
FeedBack:
只有注冊用戶登錄后才能發(fā)表評論。 | ||
![]() |
||
網(wǎng)站導航:
博客園
IT新聞
Chat2DB
C++博客
博問
管理
|
||
相關(guān)文章:
|
||
| |||||||||
日 | 一 | 二 | 三 | 四 | 五 | 六 | |||
---|---|---|---|---|---|---|---|---|---|
31 | 1 | 2 | 3 | 4 | 5 | 6 | |||
7 | 8 | 9 | 10 | 11 | 12 | 13 | |||
14 | 15 | 16 | 17 | 18 | 19 | 20 | |||
21 | 22 | 23 | 24 | 25 | 26 | 27 | |||
28 | 29 | 30 | 1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
常用鏈接
留言簿(21)
隨筆分類
- J2EE 框架(9)
- J2EE基礎(chǔ)(4)
- J2SE(43)
- Java 工具(5)
- Oracle Concept(4)
- Oracle SQL/PLSQL(9)
- Oracle 開發(fā)(13)
- Oracle 管理(4)
- Oracle 調(diào)優(yōu)
- Oracle 錯誤診斷
- RoR(19)
- UML(3)
- Unix / Linux(13)
- Web基礎(chǔ)(19)
- 其它技術(shù)(7)
- 感悟(3)
- 雜項(7)
- 架構(gòu)與性能(8)
- 模式與重構(gòu)(19)
- 灌水(8)
- 電影與音樂(16)
- 走過的路(1)
- 軟件過程與軟件方法(3)
- 陽光戶外(2)
- 項目管理(36)
隨筆檔案
- 2012年2月 (3)
- 2011年11月 (4)
- 2011年10月 (1)
- 2011年9月 (2)
- 2011年8月 (2)
- 2011年7月 (5)
- 2011年6月 (3)
- 2011年5月 (1)
- 2011年4月 (1)
- 2011年3月 (3)
- 2011年1月 (1)
- 2010年12月 (1)
- 2010年11月 (5)
- 2010年10月 (3)
- 2010年9月 (1)
- 2010年7月 (1)
- 2010年6月 (1)
- 2010年5月 (4)
- 2010年4月 (9)
- 2010年3月 (19)
- 2010年2月 (8)
- 2010年1月 (3)
- 2009年12月 (34)
- 2009年11月 (1)
- 2009年10月 (2)
- 2009年7月 (4)
- 2009年6月 (5)
- 2009年5月 (3)
- 2009年4月 (2)
- 2009年3月 (1)
- 2009年2月 (5)
- 2009年1月 (5)
- 2008年12月 (13)
- 2008年11月 (4)
- 2008年10月 (1)
- 2008年9月 (6)
- 2008年8月 (5)
- 2008年7月 (3)
- 2008年6月 (31)
- 2008年5月 (10)
- 2008年4月 (9)
- 2008年3月 (7)
- 2008年2月 (4)
- 2008年1月 (19)
BlogJava熱點博客
好友博客
搜索
最新評論

- 1.?re: 【Java基礎(chǔ)專題】編碼與亂碼(01)---編碼基礎(chǔ)[未登錄]
- 666666666666666666666這幾天正在做個類似工程編碼出現(xiàn)錯誤
- --李
- 2.?re: 【Java基礎(chǔ)專題】IO與文件讀寫---使用Apache commons IO簡化文件讀寫
- 不錯
- --阿斯蘭
- 3.?re: 【Java基礎(chǔ)專題】編碼與亂碼(03)----String的toCharArray()方法
- 多謝分享
- --thx
- 4.?re: 【Java基礎(chǔ)專題】編碼與亂碼(05)---GBK與UTF-8之間的轉(zhuǎn)換
- 評論內(nèi)容較長,點擊標題查看
- --karl
- 5.?re: 【Java基礎(chǔ)專題】編碼與亂碼(01)---編碼基礎(chǔ)[未登錄]
- 謝謝,幫了我大忙!
- --小龍