Java併發編程之競爭條件和臨界區

概述

競態條件是可能發生在臨界區中的特殊條件。臨界段是由多個線程執行的代碼段,其中線程的執行順序會影響臨界段併發執行的結果。
當多個線程執行一個臨界區的結果可能因線程執行的順序而有所不同時,臨界區被稱爲包含一個競爭條件。術語競態條件源於這樣一種比喻,即線程在臨界區中競態的結果會影響臨界區的執行結果。

競爭條件

在同一個應用程序中運行多個線程本身不會導致問題。當多個線程訪問相同的資源時,問題就出現了。例如相同的內存(變量、數組或對象)、系統(數據庫、web服務等)或文件。
事實上,只有在一個或多個線程寫入這些資源時纔會出現問題。只要資源不改變,讓多個線程讀取相同的資源是安全的。
我們創建一個Timer.java進行驗證競爭的關係:代碼如下:

/**
 * 記錄次數
 */
public class Timer{
    protected long timer;
    public void add(long value){
        this.timer += value;
    }
}

我們這裏想的結果是5,但是和結果不相符,這裏爲2.這裏發生了線程的競爭關係。
操作流程:

     * timer初始化爲0
     * 
     * thread01 -> add(2) -> 2
     * thread02 -> add(3) -> 3
     * 這兩個線程希望將值2和3添加到計數器中。
     * 因此,在兩個線程完成執行後,值應該是5。
     * 但是,由於這兩個線程的執行是交錯的,所以最終的結果是不同的

在臨界區中的競爭條件

add()方法中的代碼包含一個臨界區。當多個線程執行此臨界區時,將出現競爭條件。更正式的情況是,兩個線程競爭相同的資源,其中訪問資源的順序很重要,稱爲競爭條件。導致競爭條件的代碼段稱爲臨界段。

防止競爭條件

爲了防止出現競態條件,必須確保臨界區作爲原子指令執行。這意味着一旦一個線程執行它,其他線程就不能執行它,直到第一個線程離開臨界區。
通過在關鍵區域中進行適當的線程同步,可以避免競爭條件。線程同步可以通過使用一個同步的Java代碼塊來實現。線程同步也可以通過使用其他同步結構(如LOCK)或原子變量(如java.util.concurrent. AtomicInteger)來實現.

臨界區的吞吐量

對於較小的臨界區,使整個臨界區成爲一個同步塊可以工作。但是,對於較大的臨界區,將臨界區分解爲較小的臨界區可能是有益的,以允許多個線程執行每個較小的臨界區。這可能會減少對共享資源的爭用,從而增加總臨界區的吞吐量.代碼如下:

	public class TwoNumSums {
    private int sum1 = 0;
    private int sum2 = 0;
    public void add(int val1, int val2){
        synchronized(this){
            this.sum1 += val1;   
            this.sum2 += val2;
        }
    }
}

注意add()方法是如何將值添加到兩個不同的sum成員變量的。爲了防止競態條件,要在Java同步塊中執行求和。在這個實現中,只有一個線程可以同時執行求和
但是,由於這兩個sum變量是相互獨立的,您可以將它們的sum分解成兩個獨立的同步塊,代碼如下:

	public class TwoNumSums {
    
    private int sum1 = 0;
    private int sum2 = 0;

    private Integer sum1Lock = new Integer(1);
    private Integer sum2Lock = new Integer(2);

    public void add(int val1, int val2){
        synchronized(this.sum1Lock){
            this.sum1 += val1;   
        }
        synchronized(this.sum2Lock){
            this.sum2 += val2;
        }
    }
}

現在兩個線程可以同時執行add()方法。一個線程在第一個同步塊中,另一個線程在第二個同步塊中。這兩個同步塊在不同的對象上同步,因此兩個不同的線程可以獨立地執行這兩個塊。這樣,線程之間執行add()方法的等待時間就會減少。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章