posts - 310, comments - 6939, trackbacks - 0, articles - 3
            BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

          Think in Java 4th--Java中的volatile

          Posted on 2007-09-11 14:31 詩特林 閱讀(1723) 評論(2)  編輯  收藏 所屬分類: Think In Java 4th
          Think in Java 4th--Java中的volatile

          我們知道,在Java中設(shè)置變量值的操作,除了long和double類型的變量外都是原子操作,也就是說,對于變量值的簡單讀寫操作沒有必要進(jìn)行同步。

          這在JVM 1.2之前,Java的內(nèi)存模型實(shí)現(xiàn)總是從主存讀取變量,是不需要進(jìn)行特別的注意的。而隨著JVM的成熟和優(yōu)化,現(xiàn)在在多線程環(huán)境下volatile關(guān)鍵字的使用變得非常重要。

          在當(dāng)前的Java內(nèi)存模型下,線程可以把變量保存在本地內(nèi)存(比如機(jī)器的寄存器)中,而不是直接在主存中進(jìn)行讀寫。這就可能造成一個線程在主存中修改了一個變量的值,而另外一個線程還繼續(xù)使用它在寄存器中的變量值的拷貝,造成數(shù)據(jù)的不一致。

          要解決這個問題,只需要像在本程序中的這樣,把該變量聲明為volatile(不穩(wěn)定的)即可,這就指示JVM,這個變量是不穩(wěn)定的,每次使用它都到主存中進(jìn)行讀取。一般說來,多任務(wù)環(huán)境下各任務(wù)間共享的標(biāo)志都應(yīng)該加volatile修飾。

          Volatile修飾的成員變量在每次被線程訪問時,都強(qiáng)迫從共享內(nèi)存中重讀該成員變量的值。而且,當(dāng)成員變量發(fā)生變化時,強(qiáng)迫線程將變化值回寫到共享內(nèi)存。這樣在任何時刻,兩個不同的線程總是看到某個成員變量的同一個值。 

          Java語言規(guī)范中指出:為了獲得最佳速度,允許線程保存共享成員變量的私有拷貝,而且只當(dāng)線程進(jìn)入或者離開同步代碼塊時才與共享成員變量的原始值對比。 

          這樣當(dāng)多個線程同時與某個對象交互時,就必須要注意到要讓線程及時的得到共享成員變量的變化。 

          而volatile關(guān)鍵字就是提示VM:對于這個成員變量不能保存它的私有拷貝,而應(yīng)直接與共享成員變量交互。 

          使用建議:在兩個或者更多的線程訪問的成員變量上使用volatile。當(dāng)要訪問的變量已在synchronized代碼塊中,或者為常量時,不必使用。 

          由于使用volatile屏蔽掉了VM中必要的代碼優(yōu)化,所以在效率上比較低,因此一定在必要時才使用此關(guān)鍵字。

          請看如下示例:

           

           1package ch17_concurrency;
           2
           3
           4class UnresponsiveUI{
           5 private volatile double d=1;
           6 public UnresponsiveUI() throws Exception{
           7  while(d>0){
           8   d=d+(Math.PI+Math.E)/d;
           9  }

          10  System.in.read();
          11 }

          12}

          13
          14public class _19_ResponsiveUI extends Thread {
          15 private static volatile double d=1;
          16 public _19_ResponsiveUI(){
          17  setDaemon(true);
          18  start();
          19 }

          20 public void run(){
          21  while(true){
          22   //System.out.println(d);
          23   d=d+(Math.PI+Math.E)/d;
          24  }

          25 }

          26
          27 public static void main(String[] args) throws Exception {
          28  // TODO Auto-generated method stub
          29  //new UnresponsiveUI();
          30  new _19_ResponsiveUI();
          31  System.in.read();
          32  System.out.println(d);
          33 }

          34
          35}

          36

          評論

          # re: Think in Java 4th--Java中的volatile  回復(fù)  更多評論   

          2007-09-11 16:48 by dennis
          volatile需要強(qiáng)調(diào)的一點(diǎn)就是,它僅僅保證多線程環(huán)境下的可見性,不保證操作的原子性,舉的例子不大恰當(dāng)吧,想更多了解還是看看這個帖子

          http://www.javaeye.com/topic/109150

          # re: Think in Java 4th--Java中的volatile[未登錄]  回復(fù)  更多評論   

          2008-05-23 14:26 by dd
          簡單點(diǎn)就是線程在運(yùn)行的時候?yàn)榱颂岣咝仕员辉试S偷一點(diǎn)點(diǎn)懶,即忽視多線程的可能,不更新主存中的原本(線程使用的值是副本)。

          VOLATILE即告訴JVM,不能偷懶!

          這個特性應(yīng)該是從C移植過來的。而C是沒有線程的,所以說,JAVA的線程其實(shí)做得很勉強(qiáng)。

          因?yàn)閺恼Z義的角度講,線程的這種偷懶工作方式應(yīng)該是不被允許的。JVM首先應(yīng)該保證正確性(主存跟工作區(qū)的同步),然后再考慮性能優(yōu)化。不正確的東西,性能再好也是白搭。



          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 宁强县| 香港| 政和县| 天峨县| 沧州市| 康马县| 上蔡县| 克什克腾旗| 永清县| 洪泽县| 礼泉县| 嘉祥县| 白山市| 尼木县| 乌海市| 宜都市| 桑日县| 甘肃省| 新河县| 龙岩市| 新巴尔虎左旗| 合水县| 桃园县| 台东市| 宣威市| 北碚区| 宜黄县| 任丘市| 威信县| 绩溪县| 盘锦市| 津南区| 遂宁市| 莱芜市| 隆尧县| 南漳县| 通渭县| 北票市| 五大连池市| 顺平县| 古交市|