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