两个例子详解并发编程的可见性问题和有序性问题,通过volatile保证可见性和有序性以及volatile的底层原理——缓存一致性协议MESI和内存屏障禁止指令重排
1. 并發編程的可見性問題
2. 并發編程的有序性問題
3. 使用volatile關鍵字解決可見性問題
4. 可見性問題的本質——緩存不一致
因為cpu執行速度很快,但是內存執行速度相對于CPU很慢,那么每次從內存取數據就拖慢了CPU的執行效率。實際上,在CPU和內存中有一層緩存,程序執行時在緩存操作數據,那么另一個緩存修改的數據是不會更新到當前程序緩存中的,也就出現了緩存不一致問題,也就出現了可見性問題。簡易內存模型圖如下。
5. 有序性問題的本質——指令重排
因為CPU或者編譯器為了優化程序指令,會對沒有依賴關系的程序指令進行重排。對于單線程來說,指令沒有依賴關系,重排沒有問題,但如果是并發編程,那么指令重排是有影響的。
6. volatile是怎么解決可見性、有序性問題的呢?也就是怎么解決緩存不一致和禁止指令重排的呢?
6.1 緩存不一致問題:存在該問題是某個線程只修改自己緩存的數據,沒有將數據刷新到內存中,或者另一個線程只從自己的緩存讀取數據,沒有從內存中取數據,造成了數據“不可見”。如果有一種協議,當某個線程修改緩存數據后,數據會被刷新到內存中,同時讓其他線程的緩存數據失效,重新從內存讀取,那么就解決緩存不一致問題了。這個協議就是MESI緩存一致性協議,MESI表示緩存數據(通過緩存行存儲,64個字節)的四種狀態字母縮寫,四種狀態如下,當觸發了MESI協議,就能保證數據一致,也就是保證了數據的可見性。volatile就是通過觸發MESI協議來保證數據可見的。
① Modified:數據只在當前線程的緩存中,且緩存數據與內存數據不一致。
② Exclusive:數據只在當前線程的緩存中,且緩存與內存數據一致。
③ Shared:數據存在于多個線程的緩存中,且緩存數據與內存一致。
④ Invalid:數據無效。
6.2 禁止指令重排:對于指令重排序,我們設置某些規則,當CPU或編譯器檢測到指令存在這些規則,那么不進行指令重排,即可解決有序性問題。內存屏障對于volatile數據的讀或者寫操作時,會加入對應內存屏障來保證指令的有序性。具體有哪些內存屏障,以及內存屏障為什么是那樣的設置,這里就不多敘述了,volatile寫之前有StoreStore屏障,之后有StoreLoad屏障(萬能屏障,兼具其它三種屏障功能);volatile讀之后有LoadStore和LoadLoad屏障。
總結
以上是生活随笔為你收集整理的两个例子详解并发编程的可见性问题和有序性问题,通过volatile保证可见性和有序性以及volatile的底层原理——缓存一致性协议MESI和内存屏障禁止指令重排的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java——自己实现基础的线程池及带有任
- 下一篇: 为什么不使用volatile,其它线程也