日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

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

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

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

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


??? 我們知道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那段代碼的注釋去掉程序就能停下來了,這是什么原因呢?我的理解是:因為線程printThread是能正常執(zhí)行的,所以有兩種可能:

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

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



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

volatile

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

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

  • 也就是說在上面workThread線程sleep代碼段注釋的情況下,我們可以使用volatile來修飾stop變量,這樣的話就能強制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)容還不錯,歡迎將生活随笔推薦給好友。