java.util.concurrent.atomic vs volatile

來源:互聯網
上載者:User

java.util.concurrent.atomic.Atomic*原子類和volatile關鍵字是java中兩種常見的處理多線程下資料共用讀寫的機制。二者看似相同,但是在實際應用中有著不小的差別。

volatile關鍵字是通過本地代碼實現的寫鎖,只保證知有一個線程在寫某個資料。JVM為了提高資料存取的速度,允許每個線程在自己獨立的資料區塊,對進程中共用的資料進行私人拷貝。volatile就是保證每次讀資料時,讀的都是存在共用資料區塊裡的資料,而不是私人拷貝。然而,這種機制在有些情況下並不安全。當兩個線程T1,T2同時對volatitle int i;作i++;時,可能出現問題。i++相當於為i=i+1。

T1 LOAD i

T2 LOAD i

T1 STORE i+1

T2 STORE i+1

這裡應該執行兩次i=i+1,得到i=i+2的,但是結果確實i=i+1。

因此,這邊就有了Atomic原子類存在的價值了。Atomic類被設計來解決這個問題。

以AtomicInteger為例,public class AtomicInteger extends Number implements java.io.Serializable。

它的父類Number沒有一個Field,直接繼承與Object,方法也只有abstract的int intValue(),long longValue(),float floatValue(),double doubleValue(),和通過intValue()實現的byte byteValue(),short shortValue()。簡單的說,除了序列化外啥field都沒有都沒有。

AtomicInteger有四個field,除了序列化那個無視掉外,還剩三個。

    // setup to use Unsafe.compareAndSwapInt for updates

    private static final Unsafe unsafe = Unsafe.getUnsafe();

    private static final long valueOffset;

    static {

      try {

        valueOffset = unsafe.objectFieldOffset

            (AtomicInteger.class.getDeclaredField("value"));

      } catch (Exception ex) { throw new Error(ex); }

    }

    private volatile int value;

valueOffset只在這個靜態塊裡被寫過,從函數命名上猜測應該是擷取這個類中名為value的field到這個object的頭指標的位移(offset)。這邊用到了unsafe。

Unsafe是幹什麼的?sun.misc.Unsafe,未開源。這個名字讓我想起了C#裡的關鍵字unsafe。C#為了方便C++程式員轉C#,方便使用COM組件,給出了不安全的程式碼unsafe關鍵字。Java這個Unsafe,能的到一個field距離它Object頭的位移,對Java來說顯然是不安全的操作,他給使用者直接操作記憶體的可能。

除了objectFieldOffset(Field)外,這個類中還使用到Unsafe的putOrderedInt(Object,long,int)和compareAndSwapInt(Object,long,int,int)。從方法名和參數看,功能分別為向Object位移long位置,寫入有序整型int,和比較兩值是否相同,並填入新值。

這邊有篇IBM關於compareAndSwapInt的文檔,我寫得差不多了才看到,怨念。。。http://www.ibm.com/developerworks/cn/java/j-jtp11234/

順帶說一句,調用到compareAndSwapInt的兩個方法compareAndSet和weakCompareAndSet的在1.6裡源碼是一樣的,樣的,的。。。冗餘代碼很好玩嗎,API上寫得各種看不懂。。。

剩下一個field就是private volatile int value了。也用了volatitle,由此可以得出,Atomic類在效率上是低於直接用volatitle,能使用volatitle是,就別用Atomic了。

然後看看AtomicInteger的method吧

從Number父類繼承來的那幾個可以看作getter函數的value類,清一色的調用了get()方法,然後轉了一下類型。

    public final int get() {

        return value;

    }

直接把value扔回去了,可見Atomic類在處理讀操作時和volatitle沒啥區別。

看上去像setter函數的一共有五個:

    public final void set(int newValue) {

        value = newValue;

    }

     public final void lazySet(int newValue) {

        unsafe.putOrderedInt(this, valueOffset, newValue);

    }

    public final int getAndSet(int newValue) {

        for (;;) {

            int current = get();

            if (compareAndSet(current, newValue))

                return current;

        }

    }

    public final boolean compareAndSet(int expect, int update) {

return unsafe.compareAndSwapInt(this, valueOffset, expect, update);

    }

    public final boolean weakCompareAndSet(int expect, int update) {

return unsafe.compareAndSwapInt(this, valueOffset, expect, update);

    }

weakCompareAndSet和compareAndSet實現上沒有區別,所以無視掉吧,反正AtomicInteger自己也只用compareAndSet。。。

set(int)和直接用volatitle沒啥區別,所以只用set作寫差不多就和完全沒有用到Atomic類一樣,還多調用一次函數。

lazySet(int)調用了Unsafe.putOrderedInt,我們只能猜測是直接給記憶體把個數字寫上去的。這樣的話其實。。。我也沒覺得有啥區別,就是告訴大家一下,你用Unsafe可以把Java當C++寫嘛。。。

getAndSet(int)調用了compareAndSet(int,int),所作的基本就是不停的刷,看看自己改成了沒有,改成了救過,沒改成繼續改。這邊要出現兩個線程不停對改怎麼辦。。。

最後一個compareAndSet(int,int)才是實現Atomic類功能的地方。就是比一下預想的和實際的是不是一樣,一樣就就用新值蓋掉他,不一樣就返回個false。怎麼用呢,看看其他函數就是到了。

對比getAndIncrement()和incrementAndGet()

    public final int getAndIncrement() {

        for (;;) {

            int current = get();

            int next = current + 1;

            if (compareAndSet(current, next))

                return current;

        }

    }

    public final int incrementAndGet() {

        for (;;) {

            int current = get();

            int next = current + 1;

            if (compareAndSet(current, next))

                return next;

        }

    }

區別在於,前者返回被改動的值,後者返回改動後的值。compareAndSet使用方法如上。

關於其他的機制,可以看看http://www.ibm.com/developerworks/cn/java/j-jtp11234/,有關於幾種同步機制的效能比較。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.