天天看點

并發--先行發生原則及案例分析并發–先行發生原則及案例分析

并發–先行發生原則及案例分析

标簽(空格分隔): Java-JVM

先行發生原則

先行發生原則是判斷資料是否存在競争、線程是否安全的主要依據。
  1. 程式次序規則(Program Order Rule):在一個線程内,按照程式代碼順序,書寫在前面的操作先行發生于書寫在後面的操作。準确地說,應該是控制流順序而不是程式代碼順序,因為要考慮分支、循環等結構。
  2. 管程鎖定規則(Monitor Lock Rule):一個unlock操作先行發生于後面對于同一個鎖的lock操作。這裡必須強調的是同一個鎖,而“後面”是指時間上的先後順序。
  3. volatile變量規則(Volatile Variable Rule):對于一個volatile變量的寫操作先行發生于後面對這個變量的讀操作,這裡的“後面”同樣是指時間的先後順序。
  4. 線程啟動規則(Thread Start Rule):Thread對象的start()方法先行發生于此線程的每一個動作。
  5. 線程終止規則(Thread Termination Rule):線程中的所有操作都先行發生于對此線程的終止檢測,我們可以通過Thread.join()方法結束、Thread.isAlive()的傳回值等手段檢測到線程已經終止執行。
  6. 線程中斷規則(Thread Interrupt Rule):對線程interrupt()方法的調用先行發生于被中斷線程的代碼檢測到中斷事件的發生,可以通過Thread.interrupted()方法檢測到是否有中斷發生。
  7. 對象終結規則(Finalizer Rule):一個對象的初始化完成(構造函數執行結束)先行發生于它的finalize()方法的開始。
  8. 傳遞性(Transitivity):如果操作A先行發生于操作B,操作B先行發生于操作C,那就可以得出操作A先行發生于操作C的結論。

摘自:《深入了解Java虛拟機——JVM進階特性與最佳實踐(第2版)》

案例分析(1)–線程安全類Vector

線程安全類型Vector,隻是相對線程安全,并非絕對線程安全

private static Vector<Integer> vector = new Vector<Integer>();

public static void main(String[] args) {
    while (true) {
        for (int i = ; i < ; i++) {
            vector.add(i);
        }

    Thread removeThread = new Thread(new Runnable() {
        public void run() {
            for (int i = ; i < vector.size(); i++) {
                vector.remove(i);
            }
        }
    });

    Thread getThread = new Thread(new Runnable() {
        public void run() {
            for (int i = ; i < vector.size(); i++) {
//          嘗試加入首先判斷i是否在vector size範圍内,結果同樣報錯,
//              if (i < vector.size()) {
//                  continue;
//              }
                vector.get(i);
            }
        }
    });

    removeThread.start();
    getThread.start();

    //不要同時産生過多的線程,否則會導緻作業系統假死
        while (Thread.activeCount() > ) ;
    }
}
           
  1. 程式次序:不滿足,

    remove(i)

    get(i)

    在控制流順序沒有先行發生關系;
  2. 管程鎖定:不滿足,

    remove(i)

    get(i)

    方法都是synchronized修飾,但各自持有不同的鎖,不滿足管程鎖定要求的同一個鎖;
  3. volatile變量:不滿足,沒有volatile修飾變量,無視;
  4. 線程啟動:不滿足,

    removeThread.start()

    先與

    vector.remove(i)

    getThread.start()

    先于

    vector.get(i)

    ,但後兩者明顯沒有關系;
  5. 線程終止:不滿足;
  6. 線程中斷:不滿足;
  7. 對象終結:不滿足,不存在對象終結的關系;
  8. 傳遞性:不滿足,加入

    size()

    驗證作為參考,假定A是

    remove()

    ,B是

    size()

    驗證,C是

    get()

    ,B先于C,但A可能介乎于BC之間,也可能在B之前。是以不符合傳遞性。

結論:Vector作為相對線程安全對象,其單個方法帶Synchronized修飾,是相對線程安全的,但Vector方法之間不是線程安全的,不能保證多個方法作用下的資料一緻性。執行例子

get()

會報錯:

java.lang.ArrayIndexOutOfBoundsException