1. 程式人生 > >JAVA多線程之先行發生原則

JAVA多線程之先行發生原則

程序 sync 影響 cnblogs 代碼 之間 發生 變量 nal

一、引子  

  如果java內存模型中所有的有序性都僅僅依靠volatile和synchronized來完成,那麽有一些操作會變得很繁瑣,但我們在編寫java並發代碼時並未感覺到這一點,這是因為java語言中有個先行發生原則(happens-before),通過這個原則,我們可以通過幾條規則一攬子解決並發環境下兩個操作之間是否可能存在沖突的所有問題。

二、定義

  先行發生是java內存模型中定義的兩項做錯之間的偏序關系,如果說操作A先行發生與操作B,其實就是說在發生操作B之前,操作A產生的影響能被操作B觀察到,“影響”包括修改了內存中共享變量的值、發送了消息、調用了方法等。

三、規則
  java內存模型中“天然的”的先行發生關系規則如下:
  1、程序次序規則:
    在一個線程內,按照程序代碼順序,,書寫在前面的操作先行發生於書寫在後面的操作,準確的說,應該是控制流程序而不是程序代碼順序,因為要考慮分支、循環等結構;
  2、管程鎖規則:
    一個unlock操作先行發生於後面對同一個鎖的lock操作,這裏必須強調的是同一個鎖,“後面”指的是時間上的先後順序。
  3、volatile變量規則:
    對一個volatile變量的寫操作先行發生於後面對這個變量的讀操作,“後面”同樣是時間上的先後順序。
  4、線程啟動規則:
    Thread對象的start()方法先行發生於次線程的每一個動作;
  5、線程終止規則:
    線程中的所有操作都先行發生於對此線程的終止檢測,可以通過Thread.join()方法結束,Thread.isAlive()的返回值等手段檢測到線程已終止執行
  6、線程中斷規則:
    對線程interrupt()方法的調用先行發生於被中斷線程的代碼檢測到中斷事件的發生,可以通過Thread.interruptd()方法檢測到是否有中斷發生
  7、對象終結規則:
    一個對象的初始化完成(構造函數執行結束)先行發生於它的finalize()方法的開始
  8、傳遞性
    如果操作A先行發生於操作B,操作B先行發生於操作C,那麽就可以認為操作A先行發生於操作C。

四、示例  

如下案例:

public class TestValue {
    private int value = 0;

    public int getValue() {
        return value;
    }

    public void setValue(int value) {
        this.value = value;
    }
}

  如果線程A調用了“setValue(1)”,線程B調用了同一個對象的“getValue()”方法,那麽返回值是什麽?
    答案是不確定,因為這裏的操作不是線程安全的,它不滿足上述所有的 先行發生 規則。
  修復方法有好多種,這裏列舉較為簡單的兩種:
  1)把getter/setter方法都定義為synchronized方法
  2)把value定義為volatile變量。

JAVA多線程之先行發生原則