1.什麼是線程java
通常來講,咱們把正在計算機中執行的程序叫作"進程"(Process) ,而不將其稱爲程序(Program)。所程序員
謂"線程"(Thread),是"進程"中某個單一順序的控制流。新興的操做系統,如Mac,Windows NT,Windows 95算法
等,大多采用多線程的概念,把線程視爲基本執行單位。線程也是Java中的至關重要的組成部分之一。 瀏覽器
甚至最簡單的Applet也是由多個線程來完成的。在Java中,任何一個Applet的paint()和update()方網絡
法都是由AWT(Abstract Window Toolkit)繪圖與事件處理線程調用的,而Applet 主要的里程碑方法——多線程
init(),start(),stop()和destory() ——是由執行該Applet的應用調用的。 併發
單線程的概念沒有什麼新的地方,真正有趣的是在一個程序中同時使用多個線程來完成不一樣的任務。操作系統
某些地方用輕量進程(Lightweig ht Process)來代替線程與真正進程的類似性在於它們都是單一順序控線程
制流。然而線程被認爲輕量是因爲它運行於整個程序的上下文內,能使用整個程序共有的資源和程序環境設計
。
做爲單一順序控制流,在運行的程序內線程必須擁有一些資源做爲必要的開銷。例如,必須有執行堆
棧和程序計數器。在線程內執行的代碼只在它的上下文中起做用,所以某些地方用"執行上下文"來代替"
線程"。
2.線程屬性
爲了正確有效地使用線程,必須理解線程的各個方面並瞭解Java 實時系統。必須知道如何提供線程
體、線程的生命週期、實時系統如 何調度線程、線程組、什麼是幽靈線程(Demo nThread)。
(1)線程體
全部的操做都發生在線程體中,在Java中線程體是從Thread類繼承的run()方法,或實現Runnable接口
的類中的run()方法。當線程產生並初始化後,實時系統調用它的run()方法。run()方法內的代碼實現所
產生線程的行爲,它是線程的主要部分。
(2)線程狀態
附圖表示了線程在它的生命週期內的任什麼時候刻所能處的狀態以及引發狀態改變的方法。這圖並非
完整的有限狀態圖,但基本歸納了線程中比較感興趣和廣泛的方面。如下討論有關線程生命週期以此爲據
。
●新線程態(New Thread)
產生一個Thread對象就生成一個新線程。當線程處於"新線程"狀態時,僅僅是一個空線程對象,它還
沒有分配到系統資源。所以只能啓動或終止它。任何其餘操做都會引起異常。
●可運行態(Runnable)
start()方法產生運行線程所必須的資源,調度線程執行,而且調用線程的run()方法。在這時線程處
於可運行態。該狀態不稱爲運行態是由於這時的線程並不老是一直佔用處理機。特別是對於只有一個處
理機的PC而言,任什麼時候刻只能有一個處於可運行態的線程佔用處理 機。Java經過調度來實現多線程對處
理機的共享。
●非運行態(Not Runnable) :
當如下事件發生時,線程進入非運行態。
①suspend()方法被調用;
②sleep()方法被調用;
③線程使用wait()來等待條件變量;
④線程處於I/O等待。
●死亡態(Dead)
當run()方法返回,或別的線程調用stop()方法,線程進入死亡態 。一般Applet使用它的stop()方法
來終止它產生的全部線程。
(3)線程優先級
雖然咱們說線程是併發運行的。然而事實經常並不是如此。正如前面談到的,當系統中只有一個CPU時,
以某種順序在單CPU狀況下執行多線程被稱爲調度(scheduling)。Java採用的是一種簡單、固定的調度法
,即固定優先級調度。這種算法是根據處於可運行態線程的相對優先級來實行調度。當線程產生時,它繼
承原線程的優先級。在須要時可對優先級進行修改。在任什麼時候刻,若是有多條線程等待運行,系統選擇優
先級最高的可運行線程運行。只有當它中止、自動放棄、或因爲某種緣由成爲非運行態低優先級的線程
才能運行。若是兩個線程具備相同的優先級,它們將被交替地運行。
Java實時系統的線程調度算法仍是強制性的,在任什麼時候刻,若是一個比其餘線程優先級都高的線程的
狀態變爲可運行態,實時系統將選擇該線程來運行。
(4)幽靈線程
任何一個Java線程都能成爲幽靈線程。它是做爲運行於同一個進程內的對象和線程的服務提供者。
例如,HotJava瀏覽器有一個稱爲" 後臺圖片閱讀器"的幽靈線程,它爲須要圖片的對象和線程從文件系統
或網絡讀入圖片。
幽靈線程是應用中典型的獨立線程。它爲同一應用中的其餘對象和線程提供服務。幽靈線程的run()
方法通常都是無限循環,等待服務請求。
(5)線程組 :
每一個Java線程都是某個線程組的成員。線程組提供一種機制,使得多個線程集於一個對象內,能對它
們實行總體操做。譬如,你能用一個方法調用來啓動或掛起組內的全部線程。Java線程組由ThreadGroup
類實現。
當線程產生時,能夠指定線程組或由實時系統將其放入某個缺省的線程組內。線程只能屬於一個線程
組,而且當線程產生後不能改變它所屬的線程組。
3.多線程程序
對於多線程的好處這就很少說了。可是,它一樣也帶來了某些新的麻煩。只要在設計程序時特別當心
留意,克服這些麻煩並不算太困難。
(1)同步線程
許多線程在執行中必須考慮與其餘線程之間共享數據或協調執行狀態。這就須要同步機制。在Java
中每一個對象都有一把鎖與之對應。但Java不提供單獨的lock和unlock操做。它由高層的結構隱式實現,
來保證操做的對應。(然而,咱們注意到Java虛擬機提供單獨的monito renter和monitorexit指令來實現
lock和unlock操做。)
synchronized語句計算一個對象引用,試圖對該對象完成鎖操做, 而且在完成鎖操做前中止處理。當
鎖操做完成synchronized語句體獲得執行。當語句體執行完畢(不管正常或異常),解鎖操做自動完成。做
爲面向對象的語言,synchronized常常與方法連用。一種比較好的辦法是,若是某個變量由一個線程賦值
並由別的線程引用或賦值,那麼全部對該變量的訪問都必須在某個synchromized語句或synchronized方法
內。
如今假設一種狀況:線程1與線程2都要訪問某個數據區,而且要求線程1的訪問先於線程2, 則這時僅
用synchronized是不能解決問題的。這在Unix或WindowsNT中可用Simaphore來實現。而Java並不提供。
在Java中提供的是wait()和notify()機制。使用以下:
synchronized method - 1(...) {
call by thread 1.
//access data area;
available = true;
notify()
}
synchronized method - 2(...) { //call by thread 2.
while (!available)
try {
wait(); //wait for notify().
} catch (Interrupted Exception e) {
}
}
//access data area
}
其中available是類成員變量,置初值爲false。
若是在method-2中檢查available爲假,則調用wait()。wait()的做用是使線程2進入非運行態,而且
解鎖。在這種狀況下,method-1能夠被線程1調用。當執行notify()後。線程2由非運行態轉變爲可運行態
。當method-1調用返回後。線程2
可從新對該對象加鎖,加鎖成功後執行wait()返回後的指令。這種機制也能適用於其餘更復雜的狀況。 ;
(2)死鎖
若是程序中有幾個競爭資源的併發線程,那麼保證均衡是很重要的。系統均衡是指每一個線程在執行過
程中都能充分訪問有限的資源。系統中沒有餓死和死鎖的線程。Java並不提供對死鎖的檢測機制。對大
多數的Java程序員來講防止死鎖是一種較好的選擇。最簡單的防止死鎖的方法是對競爭的資源引入序號,
若是一個線程須要幾個資源,那麼它必須先獲得小序號的資源,再申請大序號的資源。
4.小結
線程是Java中的重要內容,多線程是Java的一個特色。雖然Java的同步互斥不如某些系統那麼豐富,
但適當地使用它們也能收到滿意的效果。
run方法返回後線程進入死亡態
死亡態(Dead)
當run()方法返回,或別的線程調用stop()方法,線程進入死亡態 。一般Applet使用它的stop()方法
來終止它產生的全部線程。
更多視頻教程,盡在麥子學院(http://www.maiziedu.com/)