線程的安全問題體現在:
- 原子性:一個或多個操作在CPU執行過程中不被中斷的特性
- 可見性:一個線程對共享變量的修改,另一個線程能立刻看到
- 有序性:程序執行的順序按照代碼的先后順序執行
導致線程存在安全問題的原因:
- 緩存導致可見性問題
- 線程切換導致原子性問題
- 編譯優化導致的有序性問題
java給出的解決方法:
- JDK Atomic開頭的原子類、synchronized、LOCK,可以解決原子性問題
- synchronized、volatile、LOCK,可以解決可見性問題
- Happens-Before 規則可以解決有序性問題
Happens-Before規則:
因為jvm會對代碼進行編譯優化,指令會出現重排序的情況,為了避免編譯優化對並發編程安全性的影響,需要happens-before規則定義一些禁止編譯優化的場景,保證並發編程的正確性。
- 程序順序性規則:指的是在一個線程內,按照程序代碼的順序,前面的代碼運行的結果能被后面的代碼可見。
- 傳遞性規則:傳遞性,指的是如果A Happens-Before於B,B Happens-Before於C,則A Happens-Before於C。這個是很好理解的。用白話說就是,如果A的操作結果對B可見,B操作結果對C可見,則A的操作結果對C也是可見的。
- volatile變量規則:指對一個volatile變量的寫操作,Happens-Before於后續對這個volatile變量的讀操作。
- 指的是一個鎖的解鎖 Happens-Before 於后續對這個鎖的加鎖。
- 線程start()規則:指的是主線程A啟動子線程B后,子線程B能看到主線程在啟動線程B前的操作。
- 線程join()規則:指的是線程A調用線程B的interrupt()方法,Happens-Before 於線程B檢測中斷事件(也就是Thread.interrupted()方法)。這個也很容易理解。
- 線程的interrupt()規則:指的是線程A調用線程B的interrupt()方法,Happens-Before 於線程B檢測中斷事件(也就是Thread.interrupted()方法)。這個也很容易理解。
- finalize()規則:指的是對象的構造函數執行、結束 Happens-Before 於finalize()方法的開始。