1. 程式人生 > 實用技巧 >突擊併發程式設計JUC系列-陣列型別AtomicLongArray

突擊併發程式設計JUC系列-陣列型別AtomicLongArray

突擊併發程式設計JUC系列演示程式碼地址:
https://github.com/mtcarpenter/JavaTutorial

上一個章節我們學習原子更新基本型別類,如果沒有印象的小夥伴可以通過底部的連結回頭看下,本章節主要介紹原子更新陣列型別。

陣列型別

陣列型別就是通過原子的方式更新數組裡的某個元素,Atomic包提供了以下4個類。

AtomicLongArray 常用方法如下

方法名 說明
long getAndIncrement(int i) 以原子方式將位置i處的元素原子設定為給定值,並返回舊值。
long incrementAndGet(int i) 以原子方式將索引i
處以原子方式自增元素,並返回增加之後的值。
long getAndDecrement(int i) 以原子方式將索引i處的元素原子並自減1,並返回舊值。
long decrementAndGet(int i) 以原子方式將索引i處的元素原子並自減1,並返回增加之後的值。
long addAndGet(int i, long delta) 以原子方式將輸入值與陣列中索引i的元素相加。
long getAndSet(int i, long newValue) 將位置i處的元素原子設定為給定值,並返回舊值。
long getAndIncrement(int i) 原子地將給定的值新增到索引i
的元素。
long get(int i) 獲取位置i的當前值。
void lazySet(int i, long newValue) 最終將位置i處的元素設定為給定值。
int length() 返回陣列的長度。
void set(int i, long newValue) 將位置i處的元素設定為給定值。
boolean compareAndSet(int i,int expect,int update) 如果當前值==預期值,則以原子方式將陣列位置i的元素設定成update值。
boolean weakCompareAndSet(int i, int expect, long update)
如果當前值==期望值,則將位置i處的元素原子設定為給定的更新值。
........ ........
JDK 1.8 新增
long getAndUpdate(int i, LongUnaryOperator updateFunction) 使用將給定函式應用給當前值和給定值的結果原子更新當前值,返回舊值
long updateAndGet(int i, LongUnaryOperator updateFunction) 使用將給定函式應用給當前值和給定值的結果原子更新當前值,返回新值
........

小試牛刀

指定大小

public class AtomicExample4 {
    /**
     * 初始化 陣列長度為 10
     */
    private static AtomicLongArray arr = new AtomicLongArray(5);

    private static LongUnaryOperator longUnaryOperator = new LongUnaryOperator() {
        @Override
        public long applyAsLong(long operand) {
            // 當前索引 + 10
            return operand + 10;
        }

    };

    private static LongBinaryOperator accumulatorFunction = new LongBinaryOperator() {

        @Override
        public long applyAsLong(long left, long right) {
            return left + right;
        }
    };

    public static void main(String[] args) {
        for (int i = 0; i < arr.length(); i++) {
            System.out.println("i-" + i + "=" + arr.get(i));
        }

        // 以原子方式給當前索引下標為(0)值加1,返回新值 (i++): 0
        System.out.println("索引 0 incrementAndGet=" + arr.getAndIncrement(0));
        // 以原子方式給當前索引下標為(0)值加1,,返回新值(++i)  兩次增加 : 2
        System.out.println("索引 0 incrementAndGet=" + arr.incrementAndGet(0));
        //以原子方式給當前索引下標為(0)值減少 1,返回舊值 (i--):2
        System.out.println("索引 0 incrementAndGet=" + arr.getAndDecrement(0));
        //以原子方式給當前索引下標為(0)值減少 1,返回舊值 (--i):0
        System.out.println("索引 0 incrementAndGet=" + arr.decrementAndGet(0));
        // 以原子方式將輸入的數值與例項中的值(AtomicLongArray(0)裡的value)相加,並返回結果 : 100
        System.out.println("索引 0 addAndGet=" + arr.addAndGet(0, 100));
        // 獲取 AtomicLongArray 的 value 100
        System.out.println("索引 0 get=" + arr.get(0));

        System.out.println("*********** JDK 1.8 ***********");
        //使用將給定函式應用給當前值和給定值的結果原子更新當前值,返回上一個值
        // 索引下標為 0 執行指定函式 結果為 100 + 10
        System.out.println("索引 0 getAndUpdate=" + arr.updateAndGet(0, longUnaryOperator));
        // 索引下標為 1 執行指定函式 結果為 0 + 10
        System.out.println("索引 1 getAndUpdate=" + arr.updateAndGet(1, longUnaryOperator));
        // 使用給定函式應用給指定下標和給定值的結果原子更新當前值,並返回結果 20
        System.out.println("索引 1 accumulateAndGet=" + arr.accumulateAndGet(1, 10, accumulatorFunction));

    }


}

執行結果如下:

i-0=0
i-1=0
i-2=0
i-3=0
i-4=0
索引 0 incrementAndGet=0
索引 0 incrementAndGet=2
索引 0 incrementAndGet=2
索引 0 incrementAndGet=0
索引 0 addAndGet=100
索引 0 get=100
*********** JDK 1.8 ***********
索引 0 getAndUpdate=110
索引 1 getAndUpdate=10
索引 1 accumulateAndGet=20

通過陣列

public class AtomicExample5 {


    public static void main(String[] args) {
        /**
         * 初始化 陣列
         */
        long arrs[] = {5, 20, 30, 40, 50};
        /**
         * 將初始化陣列的值 賦值給 AtomicLongArray
         */
        AtomicLongArray arr = new AtomicLongArray(arrs);

        System.out.println("arr length=" + arr.length());
        for (int i = 0; i < arr.length(); i++) {
            System.out.println("i-" + i + "=" + arr.get(i));
        }

        // 通過set 給指定元素賦值
        arr.set(0, 10);
        // 通過 get 獲取下標為 0 的值
        System.out.println("索引 0 get = " + arr.get(0));

        //如果"指定索引的值" =  "預期值" 就將指定的值更新為需要"更新的值"
        // 索引為 2 如果是 20 則相等,將值更新為 30
        arr.compareAndSet(2, 30, 300);
        System.out.println("compareAndSet 更新索引 2 的值= " + arr.get(2));
        // 與 compareAndSet  不管初始值是否為預期值都可能會無法更新該值。
        arr.weakCompareAndSet(2, 300, 3000);
        System.out.println("weakCompareAndSet 更新索引 2 的值= " + arr.get(2));


    }


}
  • 注意知識
    • compareAndSet: 指定 索引值和給定 預期值如果相等,則修改值為 更新值.
    • weakCompareAndSet: 此方法跟compareAndSet類似,但是不管初始值是否為預期值都可能會無法更新該值。

執行結果如下:

arr length=5
i-0=5
i-1=20
i-2=30
i-3=40
i-4=50
索引 0 get = 10
compareAndSet 更新索引 2 的值= 300
weakCompareAndSet 更新索引 2 的值= 3000

總結

通過原子的方式更新數組裡的某個元素,Atomic包提供了4個類, AtomicIntegerArrayAtomicLongArrayAtomicReferenceArrayAtomicIntegerArray,基本實現類似,在生活中使用頻率比較少,如果看過上一個章節的小夥伴應該對此章節的案例相對就是輕車熟路,還不是很熟悉的小夥伴,建議嘗試在電腦中執行案例,或者自己編碼實現。


歡迎關注公眾號 山間木匠 , 我是小春哥,從事 Java 後端開發,會一點前端、通過持續輸出系列技術文章與文會友,如果本文能為您提供幫助,歡迎大家關注、在看、 點贊、分享支援,我們下期再見!