進程:可并發執行的程序在一個數據集合上的運行過程。
線程:比進程更小的能獨立運行的基本單位。
一個進程通常對應于一個程序(但程序是一個靜態的概念,進程是動態的)。而一個進程可以由多個不同的線程做成!
進程為一個數據結構及能在其上進行的一次操作,它有兩個基本特征,一個是進程是可用有資源的獨立單位,第二個是進程同時又是一個可以獨立調度和分派的基本單位,這兩個基本屬性使之能夠獨立運行,也能夠并發運行。但是在并發運行的時候,系統還需要執行一系列操作:1、需要創建進程,并為之分配其所必需的資源。2、撤銷進程,對資源進行回收。3、進程切換,它需要保留當前進程的CPU環境和設置新選中進程的CPU環境,為此需要花費不少處理時間。正因為進程擁有資源,所以在并發執行進程的時候,在創建、撤銷和切換種,系統需要付出較大的開銷,因此,系統中設置的進程不能太多,進程切換的頻率也不能過高,這就限制了并發程度的提高。
線程是進程中的一個實體,它的基本思想是將程序的執行和資源分開,只擁有一點必不可少的資源。一個進程可用有多個線程,但它可以和同屬于同一進程的其他線程共享進程所擁有的所有的資源,同一進程中的線程之間可以并發執行。這樣的話,并發程度可以獲得顯著的提高。線程也具有許多進程所具有的特征,因此被稱為輕型進程。
---------------------------------------------------------------------------------------------------
Class Test extends Thread{
private Thread t1 = new Thread() {
public void run() {
...
}
}
private Thread t2 = new Thread() {
public void run() {
...
}
}
public void start() {
t1.start();
t2.start();
}
public void run() {
while(true) {
}
}
}
當對象Test的一個Thread進入運行時候,其他Thread處于等待狀態,所以鎖對象(Test),不是鎖Thread(t1,t2)
sleep()方法,是Thread的方法,是使線程停止一段時間的方法。在sleep 時間間隔期滿后,線程不一定立即恢復執行。這是因為在那個時刻,其它線程可能正在運行而且沒有被調度為放棄執行,除非(a)“醒來”的線程具有更高的優先級,(b)正在運行的線程因為其它原因而阻塞。
wait()方法,是Object的方法,是線程交互時,如果線程對一個同步對象x 發出一個wait()調用,該線程會暫停執行,被調對象進入等待狀態,直到被喚醒或等待時間到。
wait()/notify():調用任意對象的 wait() 方法導致線程阻塞,并且該對象上的鎖被釋放。而調用 任意對象的notify()方法則導致因調用該對象的 wait() 方法而阻塞的線程中隨機選擇的一個解除阻塞(但要等到獲得鎖后才真正可執行)。
synchronized和wait()、notify()的關系:
1.有synchronized的地方不一定有wait,notify
2.有wait,notify的地方必有synchronized.這是因為wait和notify不是屬于線程類,而是每一個對象都具有的方法,而且,這兩個方法都和對象鎖有關,有鎖的地方,必有synchronized。
一個程序調用fork函數,系統為一個新的進程準備了數據段,堆棧段,代碼段,
首先,新進程與舊進程使用同一個代碼段,因為它們的程序是相同的,
對于數據段和堆棧段,系統則復制一份給新的進程,
這樣,父進程的所有數據都可以留給子進程,但是,子進程一旦開始運行,
雖然它繼承了父進程的一切數據,但實際上數據卻已經分開,
相互之間不再有影響了,也就是說,它們之間不再共享任何數據了。
兩個進程要共享數據的話,只能使用共享內存與消息隊列等來操作。如果數據段和堆棧都很大,一次fork就要復制一次,那么fork的開銷豈不是很大?
其實一般CPU都是以“頁”為單位分配空間的,
fork函數復制這兩個段,只是“邏輯”上的,并非“物理”上的,也就是說,
實際執行fork時,物理空間上兩個進程的絕大部分數據段和堆棧段都還是共享著的,
只有一個進程寫了某個數據時,這時兩個進程之間的數據才有了區別,
系統只將有區別的“頁”從物理上也分開。系統在空間上的開銷就可以達到最小。
要方便的使用共享變量,最好使用線程方式,但是需要考慮變量的保護問題,而
使用進程的共享內存與消息隊列,就不需要用戶來保護變量,因為它們已經提供了
保護。