<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆 - 312, 文章 - 14, 評論 - 1393, 引用 - 0
    數(shù)據(jù)加載中……

    Java多線程初學(xué)者指南(6):慎重使用volatile關(guān)鍵字

    本文為原創(chuàng),如需轉(zhuǎn)載,請注明作者和出處,謝謝!

    上一篇:Java多線程初學(xué)者指南(5):join方法的使用

        volatile關(guān)鍵字相信了解Java多線程的讀者都很清楚它的作用。volatile關(guān)鍵字用于聲明簡單類型變量,如int、float、boolean等數(shù)據(jù)類型。如果這些簡單數(shù)據(jù)類型聲明為volatile,對它們的操作就會變成原子級別的。但這有一定的限制。例如,下面的例子中的n就不是原子級別的:

    package mythread;

    public class JoinThread extends Thread
    {
        
    public static volatile int n = 0;
        public void run()
        {
            
    for (int i = 0; i < 10; i++)
                
    try
            {
                    n 
    = n + 1;
                    sleep(
    3); // 為了使運行結(jié)果更隨機,延遲3毫秒

                }
                
    catch (Exception e)
                {
                }
        }

        
    public static void main(String[] args) throws Exception
        {

            Thread threads[] 
    = new Thread[100];
            
    for (int i = 0; i < threads.length; i++)
                
    // 建立100個線程
                threads[i] = new JoinThread();
            
    for (int i = 0; i < threads.length; i++)
                
    // 運行剛才建立的100個線程
                threads[i].start();
            
    for (int i = 0; i < threads.length; i++)
                
    // 100個線程都執(zhí)行完后繼續(xù)
                threads[i].join();
            System.out.println(
    "n=" + JoinThread.n);
        }
    }

         如果對n的操作是原子級別的,最后輸出的結(jié)果應(yīng)該為n=1000,而在執(zhí)行上面積代碼時,很多時侯輸出的n都小于1000,這說明n=n+1不是原子級別的操作。原因是聲明為volatile的簡單變量如果當(dāng)前值由該變量以前的值相關(guān),那么volatile關(guān)鍵字不起作用,也就是說如下的表達式都不是原子操作:

    = n + 1;
    n
    ++;

          如果要想使這種情況變成原子操作,需要使用synchronized關(guān)鍵字,如上的代碼可以改成如下的形式:
    package mythread;

    public class JoinThread extends Thread
    {
        
    public static int n = 0;

        
    public static synchronized void inc()
        {
            n
    ++;
        }
        
    public void run()
        {
            
    for (int i = 0; i < 10; i++)
                
    try
                {
                    inc(); 
    // n = n + 1 改成了 inc();
                    sleep(3); // 為了使運行結(jié)果更隨機,延遲3毫秒

                }
                
    catch (Exception e)
                {
                }
        }

        
    public static void main(String[] args) throws Exception
        {

            Thread threads[] 
    = new Thread[100];
            
    for (int i = 0; i < threads.length; i++)
                
    // 建立100個線程
                threads[i] = new JoinThread();
            
    for (int i = 0; i < threads.length; i++)
                
    // 運行剛才建立的100個線程
                threads[i].start();
            
    for (int i = 0; i < threads.length; i++)
                
    // 100個線程都執(zhí)行完后繼續(xù)
                threads[i].join();
            System.out.println(
    "n=" + JoinThread.n);
        }
    }

        上面的代碼將n=n+1改成了inc(),其中inc方法使用了synchronized關(guān)鍵字進行方法同步。因此,在使用volatile關(guān)鍵字時要慎重,并不是只要簡單類型變量使用volatile修飾,對這個變量的所有操作都是原來操作,當(dāng)變量的值由自身的上一個決定時,如n=n+1、n++等,volatile關(guān)鍵字將失效,只有當(dāng)變量的值和自身上一個值無關(guān)時對該變量的操作才是原子級別的,如n = m + 1,這個就是原級別的。所以在使用volatile關(guān)鍵時一定要謹慎,如果自己沒有把握,可以使用synchronized來代替volatile。

    下一篇:Java多線程初學(xué)者指南(7):向線程傳遞數(shù)據(jù)的三種方法
         




    Android開發(fā)完全講義(第2版)(本書版權(quán)已輸出到臺灣)

    http://product.dangdang.com/product.aspx?product_id=22741502



    Android高薪之路:Android程序員面試寶典 http://book.360buy.com/10970314.html


    新浪微博:http://t.sina.com.cn/androidguy   昵稱:李寧_Lining

    posted on 2009-03-14 16:44 銀河使者 閱讀(9419) 評論(10)  編輯  收藏 所屬分類: java 原創(chuàng)多線程

    評論

    # re: Java多線程初學(xué)者指南(6):慎重使用volatile關(guān)鍵字  回復(fù)  更多評論   

    使用volatile關(guān)鍵字時該變量必須獨立于程序的其他內(nèi)容和這個變量以前的值。
    btw:n++的動作實際由“讀,添加,寫”三個步驟組成的,并不是原子操作。
    2009-03-15 09:00 | Leo1734

    # re: Java多線程初學(xué)者指南(6):慎重使用volatile關(guān)鍵字  回復(fù)  更多評論   

    volatile的原子操作是將讀、寫合二為一了,保證了其他線程讀取變量時總是最新的,如果變量的值和自身以前的值相關(guān),則volatile不起作用,如n++、n=n-1等。
    2009-03-15 09:19 | 銀河使者

    # re: Java多線程初學(xué)者指南(6):慎重使用volatile關(guān)鍵字  回復(fù)  更多評論   

    @Leo1734
    如果從bytecode角度看,Java源代碼級的很多操作都不是原子的,javac將其編譯成bytecode時都有多步組成。n = m也是由多步組成的,不過要給n加上volatile,n=m就是原子級的操作。
    2009-03-15 09:21 | 銀河使者

    # re: Java多線程初學(xué)者指南(6):慎重使用volatile關(guān)鍵字  回復(fù)  更多評論   

    受教了,謝謝各位
    2009-03-15 11:59 | 習(xí)習(xí)

    # re: Java多線程初學(xué)者指南(6):慎重使用volatile關(guān)鍵字[未登錄]  回復(fù)  更多評論   

    volatile是保證變量對其他線程的可見性
    2009-03-16 11:46 | jbahamut

    # re: Java多線程初學(xué)者指南(6):慎重使用volatile關(guān)鍵字  回復(fù)  更多評論   

    其實我覺得這個問題應(yīng)該是線程的問題,主要是線程執(zhí)行的時間可能有兩個同時獲取這個int值,然后第一個線程增加后,第二個線程在增加,覆蓋了其值,主要是線程沒有對n 這個變量加鎖,造成多個線程同時讀取相同的值
    2009-03-16 13:21 | guming123416

    # re: Java多線程初學(xué)者指南(6):慎重使用volatile關(guān)鍵字  回復(fù)  更多評論   

    @guming123416
    至于為什么volatile在某些時候不好使,這得問JVM了,可能是實現(xiàn)機制的問題,如果想保險點,應(yīng)盡量少用volatile。thanking in java的作者也建議少用volatile。
    2009-03-16 13:52 | 銀河使者

    # re: Java多線程初學(xué)者指南(6):慎重使用volatile關(guān)鍵字  回復(fù)  更多評論   

    你上面的我兩個在JDK1.6上執(zhí)行都是n=1000啊,似乎volatile有用,這還是原子操作哈
    2009-03-19 19:21 | qiulijian

    # re: Java多線程初學(xué)者指南(6):慎重使用volatile關(guān)鍵字  回復(fù)  更多評論   

    @qiulijian
    你多運行幾次,如運行20次再說,第一個例子不同步,第二個例子是同步的
    2009-03-19 19:29 | 銀河使者

    # re: Java多線程初學(xué)者指南(6):慎重使用volatile關(guān)鍵字  回復(fù)  更多評論   

    這里有自動拆封箱操作,n的對象一直在變化。
    2015-08-26 16:40 | 皮鞋錚亮
    主站蜘蛛池模板: 精品国产免费观看久久久| 国产成人精品无码免费看| 毛片网站免费在线观看| 亚洲国产美女视频| 91短视频在线免费观看| 久久综合亚洲色HEZYO社区| a级亚洲片精品久久久久久久| 日本亚洲中午字幕乱码| 亚洲成AV人片久久| 99xxoo视频在线永久免费观看| 亚洲国产成人高清在线观看| a级毛片毛片免费观看永久| 亚洲AV无码码潮喷在线观看| 国产精品区免费视频| 精品亚洲国产成AV人片传媒| 亚洲一级毛片免费在线观看| 亚洲AV成人无码天堂| 日韩伦理片电影在线免费观看| 亚洲av片在线观看| 亚洲国产精品一区二区九九| 毛片基地看看成人免费| 久久精品国产亚洲AV网站| 99视频免费播放| 亚洲乱码一二三四区乱码| 日韩激情无码免费毛片| 精品特级一级毛片免费观看| 国产自偷亚洲精品页65页| 久久精品电影免费动漫| 亚洲精品第一综合99久久| 免费**毛片在线播放直播| 亚洲人配人种jizz| 免费中文字幕在线观看| 丁香花在线视频观看免费| 亚洲毛片免费观看| 午夜亚洲av永久无码精品| 免费人成在线观看网站| 亚洲熟伦熟女新五十路熟妇| 久久国产精品2020免费m3u8| 亚洲熟妇自偷自拍另欧美| 久久久久亚洲AV成人网人人软件| 2021国内精品久久久久精免费|