为什么不使用volatile,其它线程也能得到当前线程修改后的值,不使用volatile也不存在可见性问题?原来解决可见性问题不一定需要volatile,println也可以
1. 為什么不使用volatile,其它線程也能得到變量修改后的值
實驗代碼分析:
①初始變量a=true,b=false;
②一個線程判斷a或者b是否被改為相應邏輯,如果是,那么輸出信息。
③修改a和b的線程。
實驗結果分析:不是說沒有volatile修飾的變量存在可見性問題嗎,怎么可以得到另一個線程修改的值,不存在可見性問題嗎??
原因:其實可見性問題的造成就是因為各自從緩存取數據,而不從內存取數據,如果緩存都沒有數據,大家都使用內存的值,那么就不存在可見性問題。這里不存在可見性問題的原因就是當前變量還沒有被放入緩存,我們可以加上一點休眠,讓程序有時間把數據放入緩存,然后測試,如下。
其它博客有提到,說在線程中使用的睡眠會釋放cpu執行權,然后CPU有時間去更新工作緩存和主存內容。那我這邊通過一個簡單的for循環,讓CPU沒有時間去同步緩存和主存。
2. 為什么不使用volatile,其它線程還能得到變量修改后的值
實驗代碼分析:
① 初始變量a=0,b=false;
②然后,一個線程判斷?b 的值是否為false,是false那么循環輸出“b is false and a is ”信息,直到 b 的值變為true,輸出“b is true and a is”信息結束線程;
③然后延遲2ms,為了讓后面的線程晚于前面線程執行;
④最后,另一個線程會修改a=1,b=true。
實驗結果分析:首先控制臺輸出了一句“b is false and a is 0”,因為初始值a=0,b=false,所以正確;但是后面控制臺輸出了一句“b?is true and a is 1”,為什么???不是說沒有volatile修飾的變量是會存在可見性問題的嗎?不是說一個線程修改的值,其它線程是得不到修改后的值嗎??怎么這邊能得到呢?
在分析之前,我們需要記住兩點:第一,并發編程存在可見性問題;第二:可見性問題并不是只能通過volatile修飾來解決,也就是說——沒有volatile修飾的變量不一定存在可見性問題。
原因:既然并發編程存在可見性問題,而且這邊沒有volatile修飾,那么可見性問題是怎么解決的呢?其實這邊可見性問題是通過System.out.println語句解決的,也就是System.out.println語句觸發了MESI緩存一致性協議。我們這邊將System.out.println注釋后,運行結果出現了可見性問題,可驗證原先是System.out.println解決了可見性問題,運行結果及分析如下。
3. 其實System.out.println是通過synchronized關鍵字觸發MESI緩存一致性協議,從而解決可見性問題,如下圖。
總結:發生可見性問題,需要兩個條件,①各線程操作數據是在緩存中操作,才會存在緩存不一致;②沒有觸發緩存一致性協議。
總結
以上是生活随笔為你收集整理的为什么不使用volatile,其它线程也能得到当前线程修改后的值,不使用volatile也不存在可见性问题?原来解决可见性问题不一定需要volatile,println也可以的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 两个例子详解并发编程的可见性问题和有序性
- 下一篇: 常用的设计模式——观察者设计模式?和发布