程序是程式執行的一個執行個體,比如說,10個使用者同時執行ie,那麼就有10個獨立的程序(盡管他們共享同一個可執行代碼)。
程序的特點,每一個程序都有自己的獨立的一塊記憶體空間、一組資源系統。其内部資料和狀态都是完全獨立的。怎麼看待多程序?程序的優點是提高cpu運作效率,在同一時間内執行多個程式,即并發執行。但是從嚴格上講,也不是絕對的同一時刻執行多個程式,隻不過cpu在執行時通過時間片等排程算法不同程序高速切換。總結來說:
程序由作業系統排程,簡單而且穩定
程序之間的隔離性好,一個程序崩潰不會影響其它程序
單程序程式設計簡單
在多核情況下可以把程序和cpu進行綁定,充分利用cpu
當然,多程序也有一些缺點:
一般來說程序消耗的記憶體比較大
程序切換代價很高,程序切換也像線程一樣需要保持上一個程序的上下文環境
在web程式設計中,如果一個程序來處理一個請求的話,如果要提高并發量就要提高程序數,而程序數量受記憶體和切換代價限制
線程是程序的一個實體,是cpu排程和分派的基本機關,它是比程序更小的能獨立運作的基本機關.線程自己基本上不擁有系統資源,隻擁有一點在運作中必不可少的資源(如程式計數器,一組寄存器和棧),但是它可與同屬一個程序的其他的線程共享程序所擁有的全部資源.
同類的多個線程共享一塊記憶體空間和一組系統資源,線程本身的資料通常隻有cpu的寄存器資料,以及一個供程式執行時的堆棧。線程在切換時負荷小,是以,線程也被稱為輕負荷程序。一個程序中可以包含多個線程。
位址空間:程序内的一個執行單元;程序至少有一個線程;它們共享程序的位址空間;而程序有自己獨立的位址空間
資源擁有:程序是資源配置設定和擁有的機關,同一個程序内的線程共享程序的資源
線程是處理器排程的基本機關,但程序不是
二者均可并發執行
注: 關于并發與并行
在一開始,一個計算機隻有一個cpu,這個cpu一次也隻能運作一個任務。然而随着計算機技術的發展,一個cpu也可以“同時”運作多個任務,這就誕生了多任務。但這裡的同時并不是真正的同時,作業系統通過切換各個應用來實作cpu的共享,在cpu内部各個程式其實是交替執行的。
為了進一步提高cpu使用率,多線程便誕生了。一個程式中可以運作多個線程,多個線程可以同時執行,從整個應用角度上看,這個應用好像獨自擁有多個cpu一樣。雖然多線程進一步提高了應用的執行效率,但是由于線程之間會共享記憶體資源,這也會導緻一些資源同步問題,另外,線程之間的切換也會對資源有所消耗(後面會講到)。
這裡需要注意的是,如果一台電腦隻有一個cpu核心,那麼多線程也并沒有真正的“同時”運作,它們之間需要通過互相切換來共享cpu核心,是以,隻有一個cpu核心的情況下,多線程不會提高應用效率。但是,現代計算機一般都會有多個cpu,并且每個cpu可能還會有多個核心,是以在現代硬體資源條件下,多線程程式設計可以極大的提高應用效率。

在java程式中,jvm負責線程的排程。線程排程是值按照特定的機制為多個線程配置設定cpu的使用權。
排程的模式有兩種:分時排程和搶占式排程。分時排程是所有線程輪流獲得cpu使用權,并平均配置設定每個線程占用cpu的時間;搶占式排程是根據線程的優先級别來擷取cpu的使用權。jvm的線程排程模式采用了搶占式模式。
更複雜的設計 : 多線程在通路共享資料時需要進行同步(在java中需要使用synchronized關鍵字),某些情況下需要考慮線程的執行順序和互相配合
上下文切換: 上cpu需要從一個線程切換到另一個線程時,它需要先儲存目前線程的本地資料和程式指針,然後再加載要切換線程的本地資料和程式指針
更多的系統資源:處理需要cpu時間以外,每個線程還需要額外的記憶體空間來儲存它的本地資料棧,更需要作業系統資源來管理多個線程,是以應用程式的線程數量一定要根據實際情況合理安排
java中實作多線程,一種是繼承thread類,一種是實作runable接口。
注意:在實際啟動程序的時候,我們直接調用的并不是thread子類中run方法,而是調用的thread線程的start方法,因為線程start運作需要本地作業系統支援,start啟動線程會調用作業系統native函數來支援線程運作。
實作runnable接口比繼承thread類有更多的優勢,是以我推薦大家盡量使用實作runnable接口的形式,以下是其優點
其中阻塞又可能是由以下幾種情況造成:
調用 sleep(毫秒數),使線程進入“睡眠”狀态。在規定的時間内,這個線程是不會運作的。
用 suspend()暫停了線程的執行。除非線程收到 resume()消息,否則不會傳回“可運作”狀态。
用 wait()暫停了線程的執行。除非線程收到 nofify()或者 notifyall()消息,否則不會變成“可運作“。
線程正在等候一些 io(輸入輸出)操作完成。
線程試圖調用另一個對象的“同步”方法,但那個對象處于鎖定狀态,暫時無法使用。
阻塞指的是暫停一個線程的執行以等待某個條件發生(如某資源就緒)。java 提供了大量方法來支援阻塞,下面讓我們逐一分析。
sleep()允許指定以毫秒為機關的一段時間作為參數,它使得線程在指定的時間内進入阻塞狀态,不能得到cpu 時間,指定的時間一過,線程重新進入可執行狀态。典型地,sleep() 被用在等待某個資源就緒的情形:測試發現條件不滿足後,讓線程阻塞一段時間後重新測試,直到條件滿足為止。
兩個方法配套使用,suspend()使得線程進入阻塞狀态,并且不會自動恢複,必須其對應的resume() 被調用,才能使得線程重新進入可執行狀态。典型地,suspend() 和 resume() 被用在等待另一個線程産生的結果的情形:測試發現結果還沒有産生後,讓線程阻塞,另一個線程産生了結果後,調用 resume() 使其恢複。
yield() 使得線程放棄目前分得的 cpu 時間,但是不使線程阻塞,即線程仍處于可執行狀态,随時可能再次分得 cpu 時間。調用 yield() 的效果等價于排程程式認為該線程已執行了足夠的時間進而轉到另一個線程。
兩個方法配套使用,wait() 使得線程進入阻塞狀态,它有兩種形式,一種允許指定以毫秒為機關的一段時間作為參數,另一種沒有參數,前者當對應的 notify() 被調用或者超出指定時間時線程重新進入可執行狀态,後者則必須對應的 notify() 被調用。初看起來它們與 suspend() 和 resume() 方法對沒有什麼分别,但是事實上它們是截然不同的。差別的核心在于,前面叙述的所有方法,阻塞時都不會釋放占用的鎖(如果占用了的話),而這一對方法則相反。
在這裡需要重點介紹下wait()和notify()
首先,前面叙述的所有方法都隸屬于 thread 類,但是這一對卻直接隸屬于object 類,也就是說,所有對象都擁有這一對方法。初看起來這十分不可思議,但是實際上卻是很自然的,因為這一對方法阻塞時要釋放占用的鎖,而鎖是任何對象都具有的,調用對象的 wait() 方法導緻線程阻塞,并且該對象上的鎖被釋放。而調用對象的notify()方法則導緻因調用該對象的 wait() 方法而阻塞的線程中随機選擇的一個解除阻塞(但要等到獲得鎖後才真正可執行)。
其次,前面叙述的所有方法都可在任何位置調用,但是這一對方法卻必須在 synchronized 方法或塊中調用,理由也很簡單,隻有在synchronized 方法或塊中目前線程才占有鎖,才有鎖可以釋放。同樣的道理,調用這一對方法的對象上的鎖必須為目前線程所擁有,這樣才有鎖可以釋放。是以,這一對方法調用必須放置在這樣的 synchronized 方法或塊中,該方法或塊的上鎖對象就是調用這一對方法的對象。若不滿足這一條件,則程式雖然仍能編譯,但在運作時會出現illegalmonitorstateexception 異常。
最後,關于 wait() 和 notify() 方法再說明兩點:
把指定的線程加入到目前線程,原本兩個線程可以并發執行,join之後變成了兩個線程順序執行。比如線上程b中調用了線程a的join()方法,直到線程a執行完畢後,才會繼續執行線程b。
執行上面程式從運作結果可以看出兩個線程是順序執行的。其實是當主線程調用子線程的join()方法時,主線程變獲得了子線程對象的鎖,是以被子線程阻塞直到子線程退出。
我們可以看一下join()的源碼:
join方法實作是通過wait。當main線程調用t.join()時候,main線程會獲得線程對象t的鎖,調用該對象的wait(),直到該對象喚醒main線程,比如退出後。
注意:不要誤以為優先級越高就先執行,誰先執行還是取決于誰先取得cpu資源。
線上程操作中,也可以使用yield()方法,将一個線程的操作暫時交給其他線程執行。
線程同步問題,當各個線程共用一個資源時,有可能導緻線程同步問題。在java中,是沒有類似于pv操作、程序互斥等相關的方法的。java的程序同步是通過synchronized()來實作的,需要說明的是,java的synchronized()方法類似于作業系統概念中的互斥記憶體塊,在java中的object類型中,都是帶有一個記憶體鎖的,在有線程擷取該記憶體鎖後,其它線程無法通路該記憶體,進而實作java中簡單的同步、互斥操作。關于這部分内容,請參考我的另一篇文章:
參考文章:
<a href="http://blog.csdn.net/bzwm/article/details/3881392">http://blog.csdn.net/bzwm/article/details/3881392</a>
<a href="http://www.cnblogs.com/techyc/p/3286678.html">http://www.cnblogs.com/techyc/p/3286678.html</a>