2010/01/14

Java Concurrency(9)

Memory Consistency Errors(記憶體不一致錯誤)

Memory consistency errors發生在當不同的threads對它們要處理的相通資料以有非一致的看法,這造成memory
cosistency errors是非常複雜的,幸運地,程式設計師不需要瞭解造成這個原因的細節,所需要的只是要如何避免這
樣的情況發生的策略。

避免記憶體不一致錯誤的關鍵是瞭解happen-before relationship(發生之前關聯)

int counter = 0;

counter欄位被Thread A,B分享,假設Thread A增加counter,而Thread B快速的印出counter

System.out.println(counter);

如果兩個敘述被執行在同一個thread,我們可以安全假定被印出的值會是1,但是如果兩個敘述被執行在個別的threads
時,印出來的值就有可能是0,因為並沒有擔保thread A改變了counter對Thread B而言是可見的,除了程式設計師有
成立happen-before relationship在兩個敘述之間。

還有很多行為可以創造happen-before relationships, 其中一個就是synchronization。

我們已經看過兩種行為可以創造happen-before relationships

創造新thread的程式碼對新thread是可見的

同步方法

Java提供兩種基本的同步語法,synchronized methods和synchrnoized statements

讓發法能夠synchronized只要加上synchronized關鍵字在宣告時

public class SynchronizedCounter {
    private int c = 0;

    public synchronized void increment() {
        c++;
    }

    public synchronized void decrement() {
        c--;
    }

    public synchronized int value() {
        return c;
    }
}

如果count是一個SynchronizedCounter的實例,這最造成兩種方法同步影響

第一,不可能同時引發兩個同步方法在同一個物件上,當一個thread正在執行一個同步方法在物件上,其他的thread只能
引發同步方法在同一個物件區塊直到第一個物件完成了他的動作。

第二,當一個同步方法存在,這會自動成立happens-before relationship給任何隨之而來的同步方法呼叫在同一個
物件上,這擔保物件的狀態改變是可視的。

注意建構子不能是是同步的!會造成語法上的錯誤。

注意當建構一個將會被分享在threads間的物件,早先地小心物件的參考沒有漏出,例如假設你想要維護一個List稱作
instances含有每一個class的實例,你可以嘗試增加一行程式碼

instances.add(this);

給建構子,但是其他的thread也可以使用instances在物件建構完成之前存取物件。

同步方法用簡單的策略避免thread interference以及memory consistency errors,如果一個物件被超過一個
以上的物件可視,所有的物件變數讀寫都要被完成用synchronized方法,這個方法相當有效率,但是可能會造成liveness
問題

No comments:

Post a Comment