中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

掌握系列之并發編程-7.原子并發類

發布時間:2020-07-13 13:56:24 來源:網絡 閱讀:182 作者:學習Lr 欄目:編程語言

掌握高并發、高可用架構

第二課 并發編程

從本課開始學習并發編程的內容。主要介紹并發編程的基礎知識、鎖、內存模型、線程池、各種并發容器的使用。

第七節 原子并發類

原子 CAS ABA

大名鼎鼎的ABA問題

舉個例子:桌上的滿滿的一杯水,被打翻了,擦干凈收拾完后,再倒一杯,在別人看來以為還是之前那杯。線程1是當事人,線程2是別人,共享變量V是這一杯水,線程1和線程2同時拿到共享變量V的初始值A,各自處理;在線程1中把該值更新成B,又更新成A;線程2再來取值時發現還是A,結果又去做它的處理了。這種場景在某些情形下是不正確的,比如某商場推出活動,凡是會員卡剩余金額少于100元的,商場會給充值20元,持續2天,結果因為有的會員卡本來充了一次20,他消費了50,余額又少于100元了,這樣會再次充值20元,導致一張會員卡多次充值。

下面用代碼演示一個ABA問題

public void aba() {
    AtomicInteger abaInt = new AtomicInteger(100);

    Thread t1 = new Thread() {

        public void run() {
            abaInt.compareAndSet(100, 101);
            System.out.println(String.format("thread t1, abaInt: %s", abaInt.get()));

            abaInt.compareAndSet(101, 100);
            System.out.println(String.format("thread t1, abaInt: %s", abaInt.get()));
        }
    };

    Thread t2 = new Thread() {
        public void run() {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            boolean success = abaInt.compareAndSet(100, 101);
            System.out.println(String.format("thread t2, abaInt: %s, isSuccess: %s", abaInt.get(), success));
        }
    };

    t1.start();
    t2.start();
}
thread t1, abaInt: 101
thread t1, abaInt: 100
thread t2, abaInt: 101, isSuccess: true

在線程t2中比較的值100,其實已經不是之前的值100了,內存地址中的變量已經經歷過A -> B -> A的改變了。

ABA問題的根本原因是無法判斷變量是否真正被改變過,所以解決方案是給共享變量追加狀態,用來記錄共享變量是否被修改過。

原子類

原子類在java.util.concurrent.atomic包下,有以下一些類:

AtomicBoolean 原子更新布爾值
AtomicInteger 原子增減數字的值
AtomicLong 原子更新長數字類型的值
AtomicReference 原子更新引用類型的值

AtomicIntegerArray 原子更新數字數組的元素
AtomicLongArray 原子更新長數字數組的元素
AtomicReferenceArray 原子更新引用類型數組的元素

AtomicIntegerFieldUpdater 原子更新類的數字類型字段的值
AtomicLongFieldUpdater 原子更新類的長數字類型字段的值
AtomicReferenceFieldUpdater 原子更新類的引用類型字段的值

AtomicStampedReference 原子更新帶版本號的引用類型的值,可以解決ABA問題

原子更新字段的步驟:

  1. 由于原子更新字段的類都是抽象類,使用時需要使用靜態方法newUpdater()創建更新器,并且指定要更新的類和字段
AtomicIntegerFieldUpdater<User> upd = AtomicIntegerFieldUpdater.newUpdater(User.class, 'age');
  1. 要更新的字段必須是public volatile

原子類實現原子操作的基礎是CAS,把操作交給硬件底層實現的原子性

下面給一個避免ABA問題的代碼:

public void noAba() {
    AtomicStampedReference<Integer> noAbaInt = new AtomicStampedReference<Integer>(100, 0);

    Thread t1 = new Thread() {
        public void run() {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            noAbaInt.compareAndSet(100, 101, noAbaInt.getStamp(), noAbaInt.getStamp() + 1);
            System.out.println(String.format("thread t1, noAbaInt: %s", noAbaInt.getReference()));

            noAbaInt.compareAndSet(101, 100, noAbaInt.getStamp(), noAbaInt.getStamp() + 1);
            System.out.println(String.format("thread t1, noAbaInt: %s", noAbaInt.getReference()));
        }
    };

    Thread t2 = new Thread() {
        public void run() {
            int stamp = noAbaInt.getStamp();
            System.out.println("before stamp " + stamp);

            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("after stamp " + noAbaInt.getStamp());
            boolean success = noAbaInt.compareAndSet(100, 101, stamp, stamp + 1);
            System.out.println(String.format("thread t2, noAbaInt: %s, isSuccess: %s", noAbaInt.getReference(), success));
        }
    };

    t1.start();
    t2.start();
}
before stamp 0
thread t1, noAbaInt: 101
thread t1, noAbaInt: 100
after stamp 2
thread t2, noAbaInt: 100, isSuccess: false

可以看到線程t2更新失敗了,由于版本號不是期望的值,所以更新失敗

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

石楼县| 雷波县| 阿尔山市| 神农架林区| 杭锦后旗| 松江区| 清河县| 闸北区| 白山市| 浦城县| 新和县| 宜良县| 建始县| 阿图什市| 威远县| 通山县| 张北县| 仪陇县| 大同县| 越西县| 东宁县| 巫山县| 当涂县| 宜州市| 阳城县| 姜堰市| 巴中市| 泾阳县| 昔阳县| 突泉县| 沭阳县| 盐城市| 吉水县| 株洲县| 宜都市| 克山县| 盐山县| 婺源县| 松桃| 桦川县| 沙坪坝区|