1. 程式人生 > >001_重拾多執行緒之執行緒安全問題總結

001_重拾多執行緒之執行緒安全問題總結

什麼是執行緒安全?

當多個執行緒訪問某個類時,這個類始終都能表現出正確的行為,那麼就稱這個類是執行緒安全的。(出自併發程式設計實戰)

多個執行緒訪問某個類時,不管執行時環境採用何種排程方式或者這些執行緒將如何交替執行,並且在主調程式碼中不需要任何額外的同步或協同,這個類都能表現出正確的行為,那麼就稱呼這個類是執行緒安全的。

有幾個問題需要清楚:

  1. 併發與並行的關係:
  2. 執行緒與程序的關係:
  3. 共享變數問題:

併發(concurrent)與並行(parallel):

       這是兩個非常容易被混淆的概念。它們都可以表示兩個或者多個任務一起執行,但是偏重點有些不同。併發偏重於多個任務交替執行,而多個任務之間有可能還是序列的。而並行是真正意義上的‘同時執行’。

       並行的多個任務是真實的同時執行,而對於併發來說,這個過程只是交替的,一會兒執行任務A 一會兒執行任務B,系統會不停滴在兩者間切換。但對於外觀觀察者來說,即使多個任務之間是序列併發的,也會造成多工間是並行執行的錯覺

      所以如果系統內只有一個CPU,而使用多程序或者多執行緒任務,那麼真實環境中這些任務不可能是真實並行的,畢竟一個CPU一次只能執行一條指令,這種情況下多程序或者多執行緒就是併發的,而不是並行的(作業系統會不停切換多個任務)。真實的並行也只可能出現在擁有多個CPU的系統中(比如多核CPU)。

執行緒與程序

      對於作業系統而言,一個任務就是一個程序(process),比如開啟一個記事本就等於啟動了一個記事本程序,開啟兩個記事本就啟動了兩個記事本程序等等。

      為了達到‘同時幹多件事情’,分時作業系統是把CPU時間劃分成長短基本相同的‘時間片’,通過作業系統的管理,把這些時間片依次輪流地分配給各個使用者的各個任務使用。

    在多工處理系統中,CPU需要處理所有程式的操作,當用戶來回切換它們時,需要記錄這些程式執行到哪裡。在作業系統中,CPU切換到另一個程序的狀態;當前執行任務轉為就緒(掛起、或者刪除)狀態,另一個被選定的就緒任務成為當前任務。上下文切換就是這樣一個過程,他允許CPU記錄並恢復各種正在執行程式的狀態,使其能完成切換操作。

     在上下文切換中,CPU會停止處理當前執行的程式,並儲存當前程式執行的具體位置以便之後繼續執行。來回的切換中,我們需要記住每本書當前讀到的頁碼。在程式中,上下文切換過程中的‘頁碼’資訊是儲存在程序控制塊(PCB)中的。PCB還經常被稱作‘切換幀’。‘頁碼’資訊會一直儲存到CPU記憶體中,直到他們被再次使用。

    在一個程序內部,要同時幹很多件事,就需要同時執行多個‘子任務’,我們把程序內的這些‘子任務’稱作執行緒(Thread)。

程序當做資源分配的基本單元,把執行緒當做執行的基本單元,同一程序的多個執行緒之間共享資源。

共享變數

多個執行緒都可以訪問的變數,他們之間是可以共享一部分程序中的資料的。在JVM中,Java堆和方法區的區域是多個執行緒共享的資料區域。

Java中共有三種變數,分別是類變數,成員變數和區域性變數。分別存在於方法區,堆記憶體和棧記憶體中。

public class Variables{
    
    private static int a;
    
    private int b;

    public void test(int c){
        int d;
    }
}

 變數a就是類變數,變數b就是成員變數,而變數c和d是區域性變數。所以,變數a和b是共享變數,而變數c和變數d是區域性變數。所以,變數a和b是共享變數,變數c和d是非共享變數。此刻產生多執行緒場景問題,對於變數a和b的操作是需要考慮執行緒安全的,而對於執行緒c和d是不需要考慮的。

畫的有點難看哈。。