【面試】執行緒程式區別

南望山下磚瓦工發表於2019-03-28

個人理解

面試時候多次被問到,自己回答感覺很一般,回答了以下幾點:

  • 執行緒是獨立排程的基本單位,程式是資源分配的基本單位
  • 執行緒基本不擁有資源,只擁有一點在執行中必不可少的資源,程式擁有 CPU 資源
  • 一個程式可以包括多個執行緒,這些執行緒共享程式資源

資料總結

  1. 擁有資源

程式是資源分配的基本單位,但是執行緒不擁有資源,執行緒可以訪問同一程式的資源

  1. 排程

執行緒是獨立排程的基本單位,同一程式中,執行緒的切換不會引起程式切換,從一個程式內的執行緒切換到另一個程式內的執行緒會引起程式切換

  1. 系統開銷

建立和撤銷程式時,系統都要為之分配或回收資源,所付出的開銷遠大於建立或撤銷執行緒時的開銷。同樣的在程式切換時,也會涉及當前執行程式 CPU 環境的儲存以及新排程程式 CPU 環境的設定,而執行緒的切換隻需儲存和設定少量暫存器的內容,開銷很小

  1. 通訊方面

程式間通訊需要程式同步和互斥手段的輔助,以保證資料的一致性。而執行緒間可以通過直接讀/寫同意程式中的資料段(如全域性變數)來進行通訊。

補充

  • 執行過程中區別,每個獨立的執行緒有一個程式執行的入口、順序執行序列和程式的出口,但是執行緒不能獨立執行,必須依存在應用程式中,由應用程式提供多個執行緒執行控制
  • 邏輯角度來看,多執行緒的意義在於在一個應用程式中,有多個執行部分可以同時執行,但是作業系統沒有將這多個執行緒看做多個獨立的應用,來實現程式資源的排程和管理以及資源分配
  • 一個執行緒可以建立和撤銷另一個執行緒,同一個程式中的多個執行緒之間可以併發執行

執行緒好處

  1. 在程式內建立、終止執行緒要比建立、終止程式快得多
  2. 同一程式內的執行緒間切換比程式間切換要快,尤其是使用者級執行緒間的切換。

後續問題

  1. 執行緒資源搶佔可能出現什麼問題?

這是面試騰訊的面試題,同一程式中有多個執行緒共享資源,肯定會出現資源的不夠用,簡單來說就是可能出現執行緒死鎖,這裡我當時有點不肯定,以為只能出現程式死鎖,實際上執行緒也會出現死鎖,面試官問我的時候我就直接按照程式死鎖的來說了

  1. 如何避免這種問題出現?

這個問題就是要考察死鎖發生的條件,如何避免死鎖。我先是簡單介紹了死鎖發生的四個條件,當時也是想既然是死鎖,不管執行緒還是程式發生死鎖的條件應該是一致的,就直接說了,後面查資料證明事實就是這樣的,唯一不同之處就是死鎖的基本單元不同,一個是程式之間,一個是執行緒之間。

死鎖的四個必要條件:

  • 互斥條件:一個資源只能被一個程式(執行緒)使用
  • 請求與保持條件:一個程式(執行緒)因請求資源而阻塞時,對已獲得的資源保持不放
  • 不剝奪條件:程式(執行緒)已獲得的資源,在未完成之前,不能強行剝奪
  • 迴圈等待條件:若干程式(執行緒)之間形成一種頭尾相接的迴圈等待資源關係

死鎖案例:

package opersystem;

/**
 * @author YaboSun
 */
public class DeadLock {
    // 通過一個簡單的例子測試執行緒死鎖

    public static void main(String[] args) {
        // 執行緒a
        Thread a = new Thread(new Runnable() {
            @Override
            public void run() {
                DeadLock.method1();
            }
        });

        // 執行緒b
        Thread b = new Thread(new Runnable() {
            @Override
            public void run() {
                DeadLock.method2();
            }
        });

        a.start();
        b.start();
    }

    private static void method1() {
        synchronized (String.class) {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("執行緒 a 嘗試獲取integer.class");
            synchronized (Integer.class){

            }
        }
    }

    private static void method2() {
        synchronized (Integer.class) {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("執行緒 b 嘗試獲取 string.class");
            synchronized (String.class){

            }
        }
    }
}

複製程式碼

那麼避免死鎖的出現就是破壞其中的必要條件:

  • 破壞互斥條件:例如離線印表機技術允許若干個程式同時輸出,唯一真正請求物理印表機的程式是印表機守護程式
  • 破壞佔有和等待條件:一種實現方式是規定所有程式在開始執行前請求所需要的全部資源
  • 破壞不可搶佔條件
  • 破壞環路等待條件:給資源統一編號,程式只能按編號的順序來請求資源
  1. 銀行家演算法

參考: 一句話+一張圖說清楚銀行家演算法

當一個程式申請使用資源的時候,銀行家演算法通過試探分配給該程式資源,然後通過安全性演算法判斷分配後的系統是否處於安全狀態,若不安全則試探分配作廢,讓該程式繼續等待

如何判斷系統處於安全狀態?

如果沒有死鎖發生, 並且即使所有程式突然請求對資源的最大需求,也仍然存在某種排程次序能夠使得每一個程式執行完畢,則稱該狀態是安全的。

相關文章