多線程概念
通常線程是在系統層被實現的。java是第一個在語言中實現的。java在語言級提供了對多線程設計的支援。
程式:是電腦指令的集合,它以檔案的形式儲存在磁碟上。
進程:是一個程式在其自身的地址空間中的一次執行活動。進程是資源申請、調度和獨立啟動並執行單位,因此,它使用系統中的運行資源;而程式不能申請系統資源,不能被系統調度,也不能作為獨立啟動並執行單位,因此,它不佔用系統的運行資源。
線程:是進程中的一個單一的連續控制流程程。一個進程可以擁有多個線程。
線程又稱為輕量級進程,它和進程一樣擁有獨立的執行控制,由作業系統負責調度,區別在於線程沒有獨立的儲存空間,而是和所屬進程中的其它線程共用一個儲存空間,這使得線程間的通訊遠較進程簡單。
並發編程:在電腦編程中有一個基本概念,就是在同一時刻處理多個任務的思想。許多程式設計問題都要求程式能夠停下正在做的工作,轉而處理某個其他問題,然後再返回主進程。有許多方法可以實現這個目的。最初,程式員們用所掌握的有關機器底層的知識來編寫中斷服務程式,主進程的掛起是通過硬體中斷來觸發的。儘管這麼做可以解決問題,但是其難度太大,而且不能移植,所以使得將程式移植到新型號的機器上時,既費時又費力。有時中斷對於處理時間性強的任務是必需的,但是對於大量的其他問題,我們只是想把問題切分成多個可獨立啟動並執行部分(任務),從而提高程式的響應能力。在程式中,這些彼此獨立啟動並執行部分稱之為線程,上述概念被稱為“並發”。並發最常見的例子就是使用者介面。通過使用任務,使用者可以在撳下按鈕後快速得到一個響應,而不用被迫等待到程式完成當前任務為止。
為什麼要使用多線程?
多線程協助你寫出CPU最大利用率的高效程式。舉例來說,網路的資料傳送速率遠遠低於CPU處理能力,本地檔案系統資源的讀寫速度也遠遠低於CPU的處理能力,在傳統的單線程環境中,你的程式必須等待每一個這樣的任務完成以後才能執行下一步--儘管CPU大部分時間處於空閑。而JAVA的多線程能使你充分利用這些閒置時間。在一個單線程程式中如果出現阻塞則整個程式都可能停止運行,而在一個多線程的程式中這不會出現這樣的問題。當一個線程阻塞時,別的線程會運行,這樣可以大大的提高CPU效率。
java執行緒模式
在程式的執行過程當中,某一個時刻只能有一個線程運行,那為什麼我們在啟動多個進程或者一個進程多個線程的時候,我們看到這幾個進程或線程在同時運行呢?這是因為在單個CPU的情況下,作業系統決定會在一個極短的時間片段中執行一個線程,那麼當這個時間片段運行結束以後,系統會決定運行其他的一個線程。因為這個時間片段很短,頻繁著發生切換,給我們的感覺就好象是這幾個線程同時在運行一樣。
問題:既然在單CPU情況下,某一個時刻只能有一個線程運行,那麼我們為什麼要設計多線程呢?我們能不能夠設計多進程來代替多線程呢?
我們在程式設計的時候應該考慮到程式的可移植性,當這個程式放到多CPU平台下的時候,同時運行多個線程,從而達到真正意義上的並發運行。至於能不能用多進程代替多線程,前面就已經說明了。
java線程優先順序
java自動給每個線程安排優先順序以決定與其他線程比較時該如何對待該線程。線程的優先順序是用來決定何時從一個啟動並執行線程切換到另一個,這叫“上下文轉換”。Java使用本身的線程調度器來安排線程的運行。java的線程調度器是搶佔式的分配進程(分配給每個線程相等的CPU時間的進程)。搶佔式調度模型就是許多線程處於可以運行狀態(等待狀態),但實際上只有一個線程在運行。該線程一直運行到它終止進入可運行狀態(等待狀態),或者另一個具有更高優先順序的線程變成可運行狀態。在後一種情況下,低優先順序的線程被高優先順序的線程搶佔,高優先順序的線程獲得啟動並執行機會。
具有高優先順序的線程它會搶佔底優先順序線程啟動並執行機會,但是這個不是絕對的,一個長時間處於等待狀態的底優先順序線程仍然可能被線程調度器來選擇運行。Java線程調度器支援不同優先順序線程的搶先方式,但其本身不支援相同優先順序線程的時間片輪換。但是Java運行時系統所在的作業系統(例如:Windows2000)支援時間片的輪換,那麼Java也就支援相同優先順序線程的時間片輪換。
主線程
java程式都有的線程:主線程。當java程式啟動時,一個線程立即運行,該線程通常叫做
程式的主線程。因為他是程式開始時就執行的。主線程的重要性體現在兩方面:
1,它是產生其他子線程的線程。
2,通常他必須最後完成執行,因為它執行各種關閉動作。
主線程是可以控制的。可以由一個Thread對象控制。可以用currentThread()獲得這個主線程的引用。然後你就可以像控制其他線程那樣控制這個主線程。
比如:
class CurrentThreadDemo{
public static void main(String args[]){
Thread t=Thread.currentThread();//這樣就獲得了這個主線程的引用。
System.out.println("Current thread:"+t)
}
}
建立線程
要建立多線程,可以使用繼承thread類和實現Runnable介面。
實際上thread類也是實現了Runnable介面。
Runnable介面有一個run方法。所有實現介面Runnable的對象都要實現這個方法來建立一個線程。想要啟動這個線程都要調用對象的run方法,比如thread類中的start方法。run()方法能夠像主線程那樣調用其他方法,引用其他類,聲明變數。僅有的不同是run()在程式中確立另一個並發的現成執行入口。當run()返回時,該線程也就結束了。繼承thread也是一樣的,繼承thread的類使用要方法重載run()方法來建立線程。
thread和Runnable的區別:
為什麼java會有兩種建立子線程的方法?那一種更好?Thread類定義了多種方法可以被衍生類別重載。如果你不需要重載Thread的其他方法時,最好只實現Runnable介面。
使用isAlive()和join()
一個線程如何知道另一個線程已經結束?
有兩種方法可以判定一個線程是否結束:
1,可以在現成中調用isAlive().
2,調用join().
線程的同步
當兩個或兩個以上的線程需要共用資源,他們需要某種方法來確定資源在某一刻僅被一個線程佔用,達到此目的的過程叫做同步(synchronization).
同步有兩種方法:同步塊和同步方法。
synchronization(任何一個對象){//同步塊
//需要保護的臨界區
}
原理:在java中每一個對象都有一個監視器或者叫做鎖。當運行到synchronization(obj)的時候會判斷obj這個對象是否上鎖,如果沒有,那麼虛擬機器會給他上鎖。然後向下運行,當運行完這個塊後,才會解鎖,只有解鎖以後其餘需要共用資源的線程才能運行。在這個期間需要和這個線程共用資源的線程都掛起等待。
public synchronization void tempNameFunction(){//同步方法
//需要保護的臨界區
}
原理:當線程進入到這個方法時,會自動產生一個this對象,由this對象來上鎖。這和synchronization 塊是一樣,只不過一個是任意對象,一個是this對象。
線程間的通訊:
線程他遠離了輪詢,輪詢通常由重複監測條件的迴圈實現。一旦條件成立,就要採取適當的行動。這浪費了CPU時間。
假設資料產生器必須等待消費者完成工作才能產生新的資料。在輪詢系統中,消費者在等待生產者產生資料時會浪費很多CPU周期。一旦生產者完成工作,它將啟動輪詢,浪費更多的cpu時間等待消費者的工作結束,這樣情況不受歡迎。
為了避免輪詢,java包含了通過wait(),notify()和notifyAll()方法實現的一個處理序間通訊機制。這些方法在Object類中是用final方法實現的。所以所有的類都含有他們。這三個方法僅在synchronized方法中才能調用。
SOURCE:
http://hi.baidu.com/wwwanq/blog/item/e5b4a2d592888009a08bb701.html