什麼樣的數據會存入緩存?緩存
編譯器或CPU能夠明確知曉的,可能被常常訪問的數據。例如一個在循環體中的變量,由於這個變量須要常常訪問,若是每次都從主存中拿,那就太慢了。oop
緩存一致,是跟誰一致?線程
是跟主存一致,當主存中的對應數據發生變更的時候,CPU中的緩存也會隨之變更。例如Cache中緩存了變量x的值,當主存中的x的值變更的時候,Cache中的值也會刷新。「刷新」多是將該值標記爲「失效」,下次須要時從主存拉取,或是直接用新值覆蓋。日誌
主存的數據變更是如何被監聽到的?排序
Bus Snooping。總線窺探,只要監聽總線操做就可知道其餘CPU對主存的訪問狀況。例如監聽到x變量的寫操做,那就代表x變量的值有變更。內存
高速緩存一致這些操做誰來實現?編譯器
底層硬件實現,現代計算機都有提供此功能。編譯
那這樣是否是已經有了可見性?變量
沒有,固然若是可見性指的是「當主存值發生變化的時候,Cache能夠看到」,那確實是實現了。問題是可見性不是這麼定義的,它說的是「當一個線程對一個變量進行修改時,其餘線程都可以看到」。循環
這兩種表述方式有什麼不一樣?
其實就是「一個線程對變量A的修改」 ≠ 「主存值發生變化」。也就說,修改變量的值後,修改的只是緩存中的值,不會立刻寫入主存。
爲何不立刻寫入主存?
由於慢。因此這個寫操做會被重排序到後面,這個操做仍是會執行的,只是優先級沒那麼高。
那是否是立刻寫入主存就能實現可見性呢?
是的,只要立刻寫入主存,因爲底層提供「高速緩存一致性」,因此當內存中的變量發生變動時,其餘CPU的緩存也會隨之更新。那這樣可見性就有了。
那麼如何讓它立刻寫入主存呢?
防止重排序就能夠了,這樣寫入內存的操做就會被當即執行。通常就是加內存屏障。synchronized、volatile都依賴內存屏障。
何時須要可見性?
正常的程序變量通常都不須要可見性。除非這個變量可能被多個線程同時訪問,且你須要用這個變量來協調線程操做。那這時候這個變量才須要具備可見性。這時候若是不保證可見性,就極可能出現奇怪的問題,即有時能夠正確執行,有時又不行。爲何呢?由於有時候,這些線程恰好在同一CPU上執行,訪問的是同一個Cache,天然就能獲得正確的,也就是最新的值。可是,大多數狀況不是這樣,多個線程會在多個CPU上執行,若是不保證可見性,就可能獲得過時的值。而後你就會很奇怪,明明看日誌打印,已經改了啊,爲何其餘線程仍是沒反應過來呢?
插一句
其實緩存一致性和可見性的問題,都是由多CPU的引起的,就是由於每一個CPU都有一個Cache,因此纔有了這一堆的問題。