1. 程式人生 > 其它 >執行緒程序隨筆

執行緒程序隨筆

執行緒和程序:

程序是資源分配的最小單位,執行緒是CPU排程的最小單位

執行緒在程序下行進(單純的車廂無法執行)

一個程序可以包含多個執行緒(一輛火車可以有多個車廂)

不同程序間資料很難共享(一輛火車上的乘客很難換到另外一輛火車,比如站點換乘)

同一程序下不同執行緒間資料很易共享(A車廂換到B車廂很容易)

程序要比執行緒消耗更多的計算機資源(採用多列火車相比多個車廂更耗資源)

程序間不會相互影響,一個執行緒掛掉將導致整個程序掛掉(一列火車不會影響到另外一列火車,但是如果一列火車上中間的一節車廂著火了,將影響到所有車廂)

程序可以拓展到多機,程序最多適合多核(不同火車可以開在多個軌道上,同一火車的車廂不能在行進的不同的軌道上)

程序使用的記憶體地址可以上鎖,即一個執行緒使用某些共享記憶體時,其他執行緒必須等它結束,才能使用這一塊記憶體。(比如火車上的洗手間)-"互斥鎖"

程序使用的記憶體地址可以限定使用量(比如火車上的餐廳,最多隻允許多少人進入,如果滿了需要在門口等,等有人出來了才能進去)-“訊號量”

執行緒的狀態:

  1. 新建(NEW):新建立了一個執行緒物件。

    實現Runnable介面和繼承Thread可以得到一個執行緒類,new一個例項出來,執行緒就進入了初始狀態

  2. 可執行(RUNNABLE):執行緒物件建立後,其他執行緒(比如main執行緒)呼叫了該物件的start()方法。該狀態的執行緒位於可執行執行緒池中,等待被執行緒排程選中,獲取cpu 的使用權 。

    1. 可執行狀態只是說你資格執行,排程程式沒有挑選到你,你就永遠是可執行狀態。
    2. 呼叫執行緒的start()方法,此執行緒進入可執行狀態。
    3. 當前執行緒sleep()方法結束,其他執行緒join()結束,等待使用者輸入完畢,某個執行緒拿到物件鎖,這些執行緒也將進入可執行狀態。
    4. 當前執行緒時間片用完了,呼叫當前執行緒的yield()方法,當前執行緒進入可執行狀態。
    5. 鎖池裡的執行緒拿到物件鎖後,進入可執行狀態。
  3. 執行(RUNNING):可執行狀態(runnable)的執行緒獲得了cpu 時間片(timeslice) ,執行程式程式碼。

  4. 阻塞(BLOCKED):阻塞狀態是指執行緒因為某種原因放棄了cpu 使用權,也即讓出了cpu timeslice,暫時停止執行。直到執行緒進入可執行(runnable)狀態,才有機會再次獲得cpu timeslice 轉到執行(running)狀態。阻塞的情況分三種:

    1. 等待阻塞:執行(running)的執行緒執行o.wait()方法,JVM會把該執行緒放入等待佇列(waitting queue)中。
    2. 同步阻塞:執行(running)的執行緒在獲取物件的同步鎖時,若該同步鎖被別的執行緒佔用,則JVM會把該執行緒放入鎖池(lock pool)中。
    3. 其他阻塞:執行(running)的執行緒執行Thread.sleep(long ms)或t.join()方法,或者發出了I/O請求時,JVM會把該執行緒置為阻塞狀態。當sleep()狀態超時、join()等待執行緒終止或者超時、或者I/O處理完畢時,執行緒重新轉入可執行(runnable)狀態。
  5. 死亡(DEAD):執行緒run()、main() 方法執行結束,或者因異常退出了run()方法,則該執行緒結束生命週期。死亡的執行緒不可再次復生。

wait和sleep的區別:

sleep屬於Thread類,wait屬於Object類;sleep()方法導致了程式暫停執行指定的時間,讓出cpu該其他執行緒,但是他的監控狀態依然保持者,當指定的時間到了又會自動恢復執行狀態;在呼叫sleep()方法的過程中,執行緒不會釋放物件鎖。而當呼叫wait()方法的時候,執行緒會放棄物件鎖,進入等待此物件的等待鎖定池,只有針對此物件呼叫notify()方法後本執行緒才進入物件鎖定池準備從使用角度看,sleep是Thread執行緒類的方法,而wait是Object頂級類的方法。sleep可以在任何地方使用,而wait只能在同步方法或者同步塊中使用。

  1. sleep是Thread的靜態方法,wait是Object的方法,任何物件例項都能呼叫。
  2. sleep不會釋放鎖,它也不需要佔用鎖。wait會釋放鎖,但呼叫它的前提是當前執行緒佔有鎖(即程式碼要在synchronized中)。
  3. 它們都可以被interrupted方法中斷。

併發和並行:

併發是指一個處理器同時處理多個任務;

並行是指多個處理器或者多核的處理器同時處理多個不同的任務。

併發是邏輯上的同時發生,二並行是物理上的同時發生。

Synchornized:

  1. 修飾一個方法,修飾後的方法會成為同步方法
  2. 修飾一個類,修飾後的類生成的物件都會被資料同步
  3. 修飾一個程式碼塊,修飾後的程式碼塊會成為同步程式碼塊
  4. 修飾一個靜態方法,整個靜態方法會被同步

Lock用法:

Lock鎖使用比較靈活,需要指出鎖的起始位置和結束位置,通過Lock()和unlock()指出加鎖和解鎖;

lock之後的業務程式碼和unlock方法一定要在try,finally程式碼塊中,防止業務程式碼出現異常情況沒有解鎖,導致死鎖。

public void sale() {
  lock.lock();
  try {
    while (number > 0) {
      this.number--;
      System.out.println(Thread.currentThread().getName() + "已經賣出了" + (30-number) + "張票,還有" + number + "張票");
    }
  } finally {
    lock.unlock();
  }

}

Lock和Synchonized的區別:

  1. synchronized自動釋放鎖,Lock需要手動使用unlock手動釋放鎖
  2. synchronized是一個java關鍵字,Lock是一個介面
  3. synchronized不可以判斷鎖的狀態,Lock可以判斷鎖的狀態
  4. synchronized實現的同步比較少量,Lock實現的同步可以比較大量