多线程:happens-before原则
下面就來具體介紹下happens-before原則(先行發生原則):
·????????程序次序規則:一個線程內,按照代碼順序,書寫在前面的操作先行發生于書寫在后面的操作
·????????鎖定規則:一個unlock操作先行發生于后面對同一個鎖的lock操作。(先解鎖,才可以在后面繼續上鎖)
·????????volatile變量規則:對一個變量的寫操作先行發生于后面對這個變量的讀操作
·????????傳遞規則:如果操作A先行發生于操作B,而操作B又先行發生于操作C,則可以得出操作A先行發生于操作C
·????????線程啟動規則:Thread對象的start()方法先行發生于此線程的每個一個動作
·????????線程中斷規則:對線程interrupt()方法的調用先行發生于被中斷線程的代碼檢測到中斷事件的發生
·????????線程終結規則:線程中所有的操作都先行發生于線程的終止檢測,我們可以通過Thread.join()方法結束、Thread.isAlive()的返回值手段檢測到線程已經終止執行(所有終結的線程都不可再用)
·????????對象終結規則:一個對象的初始化完成先行發生于他的finalize()方法的開始
這8條原則摘自《深入理解Java虛擬機》。
這8條規則中,前4條規則是比較重要的,后4條規則都是顯而易見的。
?
下面我們來解釋一下前4條規則:
對于程序次序規則來說,我的理解就是一段程序代碼的執行在單個線程中看起來是有序的。注意,雖然這條規則中提到“書寫在前面的操作先行發生于書寫在后面的操作”,這個應該是程序看起來執行的順序是按照代碼順序執行的,因為虛擬機可能會對程序代碼進行指令重排序。雖然進行重排序,但是最終執行的結果是與程序順序執行的結果一致的,它只會對不存在數據依賴性的指令進行重排序。因此,在單個線程中,程序執行看起來是有序執行的,這一點要注意理解。事實上,這個規則是用來保證程序在單線程中執行結果的正確性,但無法保證程序在多線程中執行的正確性。
第二條規則也比較容易理解,也就是說無論在單線程中還是多線程中,同一個鎖如果出于被鎖定的狀態,那么必須先對鎖進行了釋放操作,后面才能繼續進行lock操作。
第三條規則是一條比較重要的規則,也是后文將要重點講述的內容。直觀地解釋就是,如果一個線程先去寫一個變量,然后一個線程去進行讀取,那么寫入操作肯定會先行發生于讀操作。
第四條規則實際上就是體現happens-before原則具備傳遞性。
一個操作,時間上先發生不代表這個操作就一定是先行發生。反過頭來也一樣。一個操作先行發生也不一定這個操作就是死時間上的先發生!!!
時間先后順序和先行發生原則之間沒有基本沒有太大的關系!所以我們在衡量并發安全問題的時候不要受到時間順序的干擾,一切順序必須先以先行發生原則進行!?
?
再來一遍
?
先行發生原則? ?====》》》》? ? ?happens-before原則
上面提到了可以用 volatile 和 synchronized 來保證有序性。除此之外,JVM 還規定了先行發生原則,讓一個操作無需控制就能先于另一個操作完成。
1. 單一線程原則
Single Thread rule
在一個線程內,在程序前面的操作先行發生于后面的操作。
?
2. 管程鎖定規則
Monitor Lock Rule
一個 unlock 操作先行發生于后面對同一個鎖的 lock 操作。
?
3. volatile 變量規則
Volatile Variable Rule
對一個 volatile 變量的寫操作先行發生于后面對這個變量的讀操作。
?
4. 線程啟動規則
Thread Start Rule
Thread 對象的 start() 方法調用先行發生于此線程的每一個動作。
?
5. 線程加入規則
Thread Join Rule
Thread 對象的結束先行發生于 join() 方法返回。
?
6. 線程中斷規則
Thread Interruption Rule
對線程 interrupt() 方法的調用先行發生于被中斷線程的代碼檢測到中斷事件的發生,可以通過 interrupted() 方法檢測到是否有中斷發生。
7. 對象終結規則
Finalizer Rule
一個對象的初始化完成(構造函數執行結束)先行發生于它的 finalize() 方法的開始。
8. 傳遞性
Transitivity
如果操作 A 先行發生于操作 B,操作 B 先行發生于操作 C,那么操作 A 先行發生于操作 C。
總結
以上是生活随笔為你收集整理的多线程:happens-before原则的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 并发编程:原子性问题,可见性问题,有序性
- 下一篇: 多线程:volatile