【Java並發入門】02 Java內存模型:看Java如何解決可見性和有序性問題

如何解決其中的可見性有序性導致的問題,這也就引出來了今天的主角——Java 內存模型。

一、什麼是 Java 內存模型?

導致可見性的原因是緩存,導致有序性的原因是編譯優化,那解決可見性、有序性最直接的辦法就是禁用緩存和編譯優化,但這樣雖然解決了問題,但也導致帶來的性能優化都沒了。

因此,解決方案是:提出一套規則和方法,是程序員能在該禁用的時候禁用,不該禁用的時候不禁用。

Java 內存模型規範就是來解決這個問題的 —— 提供按需禁用緩存和編譯優化的方法
具體來說,這些方法包括 volatile、synchronized 和 final 三個關鍵字,以及六項 Happens-Before 規則,這也正是本期的重點內容。

二、Happens-Before 規則

Q:如何理解 Happens-Before 呢?
A:前面一個操作的結果對後續操作是可見的。但不能理解為前一個操作發生在後續操作的前面。
只要最終語義是對的,編譯器怎麼優化都行。

1、程序的順序性規則
這條規則是指在一個線程中,按照程序順序,前面的操作 Happens-Before 於後續的任意操作。

2、volatile 變量規則
這條規則是指對一個 volatile 變量的寫操作, Happens-Before 於後續對這個 volatile 變量的讀操作。

3、傳遞性
這條規則是指如果 A Happens-Before B,且 B Happens-Before C,那麼 A Happens-Before C。

4、管程中鎖的規則
這條規則是指對一個鎖的解鎖 Happens-Before 於後續對這個鎖的加鎖。

5、線程 start() 規則
這條是關於線程啟動的。它是指主線程 A 啟動子線程 B 後,子線程 B 能夠看到主線程在啟動子線程 B 前的操作。

6、線程 join() 規則
它是指主線程 A 等待子線程 B 完成(主線程 A 通過調用子線程 B 的 join() 方法實現),當子線程 B 完成後(主線程 A 中 join() 方法返回),主線程能夠看到子線程的操作。當然所謂的「看到」,指的是對共享變量的操作。

疑惑

Q:volatile、synchronized 和 final 能理解是提供給程序員用的,六項 Happens-Before 規則是約束誰的呢?
A:這是給程序員的保障,按照提供的規則寫,就能保證 Happens-Before 的語義。

參考文章:

Java內存模型以及happens-before規則