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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

浅析volatile原理及其使用

發布時間:2025/6/17 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 浅析volatile原理及其使用 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

經常在網上看一些大牛們的博客,從中收獲到一些東西的同時會產生一種崇拜感,從而萌發了自己寫寫博客的念頭.然而已經有這個念頭很久,卻始終不敢下手開始寫.今天算是邁出了人生的一大步^_^!


volatile的定義及其實現

定義:如果一個字段被聲明成volatile,那么java線程內存模型將確保所有線程看到的這個變量的值都是一致的.

從它的定義當中咱們也可以了解到volatile具有可見性的特性.但它具體是如何保證其可見性的呢?

先看一段JIT編譯器生成的匯編指令

//Java代碼如下 instance = new Singleton(); //這里instance是volatile變量 //反匯編后 0x01a3de1d: movb $0x0,0x1104800(%esi); 0x01a3de24: lock add1 $0x0,(%esp); 復制代碼

有volatile修飾的變量在進行寫操作時會出現第二行反匯編代碼,重點在lock這個指令.它有兩個目的:

  • 立即回寫當前處理器緩存行的值到內存.
  • 其他所有cpu緩存了該地址的數據將會失效.
  • 這里大家也許會有疑問,有沒有可能存在多個cpu一起回寫數據?

    答案是不會的.雖然cpu鼓勵多個處理器可以有競爭,但是總線會對競爭做出裁決,只會有一個cpu獲取優先權.其他處理器會被總線禁止,處于阻塞狀態.如下圖:

    對于第二點,其他cpu緩存該地址的數據失效后想要再次使用的話就必須得從主內存中重新讀取,這樣就能保證再次執行計算時所獲取的值是最新的,也可以認為所有CPU的緩存是一致的,這也就證明了volatile修飾的字段是可見的.


    可見性不代表在并發下是安全的

    這里咱們先引進一段代碼:

    /*** volatile 變量自增運算** @author mars*/ public class VolatileTest {public static volatile int count = 0;public static void increase() {count++;}private static final int THREAD_COUNTS = 20;public static void main(String[] args) throws InterruptedException {CountDownLatch latch = new CountDownLatch(THREAD_COUNTS);Thread[] threads = new Thread[THREAD_COUNTS];for (int j = 0; j < THREAD_COUNTS; j++) {threads[j] = new Thread(new Runnable() {@Overridepublic void run() {for (int i = 0; i < 10000; i++) {increase();}latch.countDown();}});threads[j].start();}//等待所有的線程執行結束latch.await();System.out.println(count);} } 復制代碼

    這段代碼供發起了20個線程,對count變量進行了10000次自增操作,如果volatile修飾的字段在并發下是安全的話,講道理最終結果都會是200000,但經過測試發現,每次的輸出結果都會不一樣.但具體是什么原因造成的?

    其實最主要的問題是出在increase()這個自增方法上,這個操作不是一個原子操作,也就是不是一步就能操作完成的,其中會經歷count值入棧,add,出棧,到操作線程緩存,最終到內存等等一系列步驟.當A線程其執行這些指令時,B線程正好將數據同步到了主內存中,此時A線程棧頂的數據就會變成過期數據,然后A線程就會將較小的值同步到主內存中.


    如何正確的運用volatile

    要想運用好volatile修飾符,需要保證運用場景符合下述規則:

  • 運算結果不依賴變量的當前值.
  • 該變量不需要和其他變量共同參與約束.
  • 例如使用volatile變量來控制并發就很合適:

    volatile boolean shutdownWork;public void shutdowm(){shutdownWork = true;}public void doWork(){while (!shutdownWork){//execute task}} 復制代碼

    上面這段代碼運行結果并無需依賴shutdownWork的值,但是只要shutdownWork的值一旦經過改變,便會立即被其他所有線程所感知,然后停止執行任務.


    小知識點

    在多處理器下,為了保證各個處理器的緩存是一致的,處理器會使用嗅探技術來保證它的內部緩存,系統內存和其他處理器的緩存的數據在總線上保持一致.如果通過嗅探檢測到其他處理器打算寫內存地址,而這個地址當前處于共享狀態,那么正在嗅探的處理器將使它的緩存無效,在下次訪問相同的內存地址時,強制執行緩存行填充,也就是從內存中重新讀取該內存地址指向的值.


    End

    總結

    以上是生活随笔為你收集整理的浅析volatile原理及其使用的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。