熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java高級技術 >> 正文

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

2013-11-23 19:41:06  來源: Java高級技術 

  volatile關鍵字相信了解Java多線程的讀者都很清楚它的作用volatile關鍵字用於聲明簡單類型變量如intfloatboolean等數據類型如果這些簡單數據類型聲明為volatile對它們的操作就會變成原子級別的但這有一定的限制例如下面的例子中的n就不是原子級別的

   package mythread;

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

            }
            catch (Exception e)
            {
            }
    }

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

        Thread threads[] = new Thread[];
        for (int i = ; i < threadslength; i++)
            // 建立個線程
            threads[i] = new JoinThread();
        for (int i = ; i < threadslength; i++)
            // 運行剛才建立的個線程
            threads[i]start();
        for (int i = ; i < threadslength; i++)
            // 個線程都執行完後繼續
            threads[i]join();
        Systemoutprintln(n= + JoinThreadn);
    }
}

  如果對n的操作是原子級別的最後輸出的結果應該為n=而在執行上面積代碼時很多時侯輸出的n都小於這說明n=n+不是原子級別的操作原因是聲明為volatile的簡單變量如果當前值由該變量以前的值相關那麼volatile關鍵字不起作用也就是說如下的表達式都不是原子操作

   n = n + ;
n++;

  如果要想使這種情況變成原子操作需要使用synchronized關鍵字如上的代碼可以改成如下的形式

   package mythread;

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

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

            }
            catch (Exception e)
            {
            }
    }

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

        Thread threads[] = new Thread[];
        for (int i = ; i < threadslength; i++)
            // 建立個線程
            threads[i] = new JoinThread();
        for (int i = ; i < threadslength; i++)
            // 運行剛才建立的個線程
            threads[i]start();
        for (int i = ; i < threadslength; i++)
            // 個線程都執行完後繼續
            threads[i]join();
        Systemoutprintln(n= + JoinThreadn);
    }
}

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


From:http://tw.wingwit.com/Article/program/Java/gj/201311/27293.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.