日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

为了防止程序重排序,慎用volatile

發(fā)布時間:2025/3/17 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 为了防止程序重排序,慎用volatile 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

??? 之前在InfoQ看到一篇關(guān)于java重排序的一篇文章,覺得里面有些知識寫得太絕對了,于是想通過實(shí)際程序來說明一下:

??? 關(guān)于java重排序,這里就不做介紹了,我們知道JVM底層封裝了與OS的交互,它內(nèi)部有自己的一套類似于OS的內(nèi)存模型,程序重排序的設(shè)計(jì)思路基本上是來源于OS跟硬件層面的設(shè)計(jì)。下面直接入正題吧!


??? 我們知道JVM給每個線程分配了自己的內(nèi)存空間,也就是說在變量存儲方面,分為主內(nèi)存和線程工作內(nèi)存,也就是說,所有線程共享主內(nèi)存,每個線程都有自己的工作內(nèi)存。程序執(zhí)行的時候是去工作內(nèi)存里面取值還是去主內(nèi)存里面取值呢?下面以代碼為例:

public?class?DemoWork?{private?boolean?stop=false;private?boolean?start=true;public?void?workThread()?throws?InterruptedException{Thread?workThread=new?Thread(new?Runnable()?{private?int?i=0;@Overridepublic?void?run()?{//?TODO?Auto-generated?method?stubwhile(!stop){i++;/*try?{Thread.sleep(10);}?catch?(InterruptedException?e)?{//?TODO?Auto-generated?catch?blocke.printStackTrace();}*/}start=false;}});workThread.start();Thread.sleep(1000);stop=true;Thread?printThread=new?Thread(new?Runnable()?{private?int?i=0;@Overridepublic?void?run()?{//?TODO?Auto-generated?method?stubwhile(stop&&start){System.out.println("stop?is:"+stop);try?{Thread.sleep(10);}?catch?(InterruptedException?e)?{//?TODO?Auto-generated?catch?blocke.printStackTrace();}}}});printThread.start();}/***?@param?args*?@throws?InterruptedException?*/public?static?void?main(String[]?args)?throws?InterruptedException?{//?TODO?Auto-generated?method?stubDemoWork?dw=new?DemoWork();dw.workThread();}}

上面的代碼是不會停下來的,但是如果把sleep那段代碼的注釋去掉程序就能停下來了,這是什么原因呢?我的理解是:因?yàn)榫€程printThread是能正常執(zhí)行的,所以有兩種可能:

  • 線程workThread里面工作線程stop變量值沒有收到主存的同步,而它一直取的是自己工作線程里面的stop值

  • 主線程更新stop沒有更新主內(nèi)存,以至于主內(nèi)存里面保存的stop值一直是false



? 以上第二點(diǎn)我覺得是可以排除的,因?yàn)榫€程printThread里面的值stop值是true,所以造成以上情況第一點(diǎn)的可能性大一點(diǎn),那為什么把workThread里面的睡眠去掉之后程序又能正常退出呢?那就應(yīng)該是在執(zhí)行這些語句的時候主內(nèi)存更新了工作內(nèi)存的緣故了(執(zhí)行打印語句也會推出,至于這里面的原因是什么,暫時還沒看到相關(guān)的資料,可能跟JVM的重排序規(guī)則有關(guān)系,但是規(guī)則到底是怎樣的呢?),接下來我們來說說volatile

volatile

  • (適用于Java所有版本)讀和寫一個volatile變量有全局的排序。也就是說每個線程訪問一個volatile作用域時會在繼續(xù)執(zhí)行之前讀取它的當(dāng)前值,而不是(可能)使用一個緩存的值。(但是并不保證經(jīng)常讀寫volatile作用域時讀和寫的相對順序,也就是說通常這并不是有用的線程構(gòu)建)。

  • (適用于Java5及其之后的版本)volatile的讀和寫建立了一個happens-before關(guān)系,類似于申請和釋放一個互斥鎖[7]。

  • 也就是說在上面workThread線程sleep代碼段注釋的情況下,我們可以使用volatile來修飾stop變量,這樣的話就能強(qiáng)制workThread線程去主內(nèi)存里面取stop的值了,但是這樣做的話在高并發(fā)現(xiàn)會造成性能問題。之前看了很多的開源代碼,里面解決以上主內(nèi)存與工作內(nèi)存不同步的方式基本上是采用volatile修飾變量解決的。我在想,既然volatile在并發(fā)情況下會造成性能問題,在workThread循環(huán)快里面執(zhí)行什么類型的代碼快能方便JVM更好的同步主內(nèi)存跟工作內(nèi)存的值,那樣的話,在高并發(fā)下,就能更快的提高程序性能了。

    轉(zhuǎn)載于:https://blog.51cto.com/chenyanxi/1577101

    總結(jié)

    以上是生活随笔為你收集整理的为了防止程序重排序,慎用volatile的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。