1. 程式人生 > >Java併發程式設計札記-(三)JUC原子類-05原子方式更新類的指定volatile欄位

Java併發程式設計札記-(三)JUC原子類-05原子方式更新類的指定volatile欄位

AtomicReferenceFieldUpdater、AtomicIntegerFieldUpdater和AtomicLongFieldUpdater是基於反射的實用工具,可以提供對關聯欄位型別的訪問。例如AtomicLongFieldUpdater可以對指定類的指定volatile long欄位進行原子更新。本文以AtomicLongFieldUpdater為例來學習。

API

//構造方法摘要
protected   AtomicLongFieldUpdater() 
          //受保護的無操作構造方法,供子類使用。

//方法摘要
 long   addAndGet(T obj, long
delta) //以原子方式將給定值新增到此更新器管理的給定物件的欄位的當前值。 abstract boolean compareAndSet(T obj, long expect, long update) //如果當前值 == 預期值,則以原子方式將此更新器所管理的給定物件的欄位設定為給定的更新值。 long decrementAndGet(T obj) //以原子方式將此更新器管理的給定物件欄位當前值減 1。 abstract long get(T obj) //獲取此更新器管理的在給定物件的欄位中保持的當前值。
long getAndAdd(T obj, long delta) //以原子方式將給定值新增到此更新器管理的給定物件的欄位的當前值。 long getAndDecrement(T obj) //以原子方式將此更新器管理的給定物件欄位當前值減 1。 long getAndIncrement(T obj) //以原子方式將此更新器管理的給定物件欄位的當前值加 1。 long getAndSet(T obj, long newValue) //將此更新器管理的給定物件的欄位以原子方式設定為給定值,並返回舊值。
long incrementAndGet(T obj) //以原子方式將此更新器管理的給定物件欄位當前值加 1。 abstract void lazySet(T obj, long newValue) //最後將此更新器管理的給定物件的欄位設定為給定更新值。 static <U> AtomicLongFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) //為物件建立並返回一個具有給定欄位的更新器。 abstract void set(T obj, long newValue) //將此更新器管理的給定物件的欄位設定為給定更新值。 abstract boolean weakCompareAndSet(T obj, long expect, long update) //如果當前值 == 預期值,則以原子方式將此更新器所管理的給定物件的欄位設定為給定的更新值。 //以下是JDK1.8新增的部分 long getAndUpdate(int i, LongUnaryOperator updateFunction) //將當前值以原子方式更新為updateFunction方法的結果,並返回更新前的值 long updateAndGet(int i, LongUnaryOperator updateFunction) //將當前值以原子方式更新為updateFunction方法的結果,並返回更新後的值 long getAndAccumulate(int i, long x, LongBinaryOperator accumulatorFunction) //將當前值以原子方式更新為updateFunction方法的結果(方法引數為x和當前值),並返回更新前的值 long accumulateAndGet(int i, long x, LongBinaryOperator accumulatorFunction) //將當前值以原子方式更新為updateFunction方法的結果(方法引數為x和當前值),並返回更新後的值

例1:AtomicLongFieldUpdater原子方式更新類的指定volatile欄位

:通常情況下,在Java中的++i或者-–i不是執行緒安全的。一般情況下,只能加鎖才能保證上述操作的原子性。有了AtomicLongFieldUpdater後,使用AtomicLongFieldUpdater就可以保證上述操作的原子性。

Counter是一個計數器類。

class Counter extends Thread {
    private static long counter = 0;

    public static long addOne() {
        return ++counter;
    }
}

在多執行緒環境下測試其是否可用。

public class CounterTest {
    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            Thread thread = new Thread() {
                public void run() {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    if (Counter.addOne() == 100) {
                        System.out.println("計數器值最終值為100");
                    }
                }
            };
            thread.start();
        }
    }
}

測試程式,在連續執行100次++counter後,判斷計數器值是否為100,如果為100就列印計數器值最終值為100,否則就什麼都不列印。
數次執行程式後,發現大多數結果是什麼都沒有列印,說明次計數器在多執行緒環境下不可用。
修改計數器類。

class Counter {
    private volatile long counter = 0;

    static AtomicLongFieldUpdater updater = AtomicLongFieldUpdater.newUpdater(Counter.class, "counter");
    static Counter safeCounter = new Counter ();

    public static long addOne() {
        return updater.addAndGet(safeCounter, 1);
    }
}

在多執行緒環境下測試其是否可用。數次執行程式後,發現結果全部為計數器值最終值為100。

實現原理

與其他原子類一樣,AtomicLongFieldUpdater也是基於CAS實現的。

AtomicReferenceFieldUpdater、AtomicIntegerFieldUpdater與AtomicLongFieldUpdater很相似,就不多做介紹了。

本文就講到這裡,想了解Java併發程式設計更多內容請參考:

END.