java异步线程内存可见性实验
【README】
本文演示了內存可見性的場景,以及解決方法;
相關定義如下(轉自java并發編程實戰,一本好書,強烈推薦):
【1】內存可見性問題例子
【1.1】測試用例
public class TestVisibility {public static void main(String[] args) {Robot robot = new Robot();new Thread(()->{try {// 睡眠模擬業務邏輯處理TimeUnit.MILLISECONDS.sleep(1000);} catch (InterruptedException e) {}robot.init();}).start();System.out.println(robot.getAge());int count = 0;while(robot.getAge() == 0) {++count;}System.out.println("主線程【成功】讀取子線程設置的age值");} } /*** @description 機器人* @author xiao tang* @date 2022/2/13*/ class Robot {int age = 0;public void init() {this.age = 10;}public int getAge() {return this.age;} }打印結果:
0
while進入了死循環
【1.2】 分析
子線程睡眠一秒,使得主線程可以先從主存(內存)讀取到age的值,并放入自己的緩存;
然后子線程再更新age的值并同步到主存;
由于主線程不從主存讀取age,所以它使用的是age的失效值(臟數據);
【2】解決方法
1)方法1, 為 Robot.age 添加 volative 修飾符; 以保證age的內存可見性;
2)方法2,為 getAge() 方法 添加 synchronized 修飾符,以保證age的內存可見性;
3)方法3,while循環體,即++count下面添加一條 打印語句,如下:
while(robot.getAge() == 0) {++count;System.out.println(count);}為什么添加 System.out.println(count); 后就可以解決內存可見性問題了?
因為 pringln 內部是 synchronized 代碼塊來實現的;如下:
public void println(int x) {synchronized (this) {print(x);newLine();}}即 方法3與方法2的原理一樣,借助 synchronized 能夠保證內存可見性的原理;?
【3】補充
1,對于睡眠語句, TimeUnit.MILLISECONDS.sleep(1000); 我們可以測試出 內存可見性效果;
但是,如果把 1000 換為 1 或 10, 500, ...... 會產生不同的效果,這就類似于不同業務邏輯有著不同的耗時; 即 內存可見性問題會因為不同的耗時而表現出不同的結果;
這就很麻煩了,因為如果業務邏輯真正存在可見性問題,但可能沒有測試出來,但生產上又存在發生可能性;
我們唯一需要做的就是,在多線程編程時,保證內存可見性,安全的發布共享對象;
【3.1】 happers-before
以下內容轉自 :
關于Java內存可見性的探究實驗遇到的意外和happens-before - 簡書
happens-before字面翻譯過來就是先行發生,A happens-before B 就是A先行發生于B?
不準確!在Java內存模型中,happens-before
應該翻譯成:前一個操作的結果可以被后續的操作獲取。講白點就是前面一個操作把變量a賦值為1,那后面一個操作肯定能知道a已經變成了1。
我們再來看看為什么需要這幾條規則?
因為我們現在電腦都是多CPU,并且都有緩存,導致多線程直接的可見性問題。
所以為了解決多線程的可見性問題,就搞出了happens-before原則,讓線程之間遵守這些原則。編譯器還會優化我們的語句,所以等于是給了編譯器優化的約束。不能讓它優化的不知道東南西北了!。
1)關于 happens-before,有以下8條規則:
詳細請看:https://segmentfault.com/a/1190000011458941
2)本文中鎖的happens-before的作用:
由于happens-before原則,在獲取鎖時,主線程會使自己CPU的緩存失效,重新從主內存中讀取變量的值。這樣,子線程中的操作結果就會被主線程感知到了,從主內存中獲取了最新的a值。
總結
以上是生活随笔為你收集整理的java异步线程内存可见性实验的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: jvm的client与server工作模
- 下一篇: 微信公众号的网页怎么弄的(微信公众号的网