欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java的Atomic原子類詳解

 更新時(shí)間:2023年09月25日 12:25:54   作者:2201_75761617  
這篇文章主要介紹了Java的Atomic原子類詳解,本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

Java SDK 并發(fā)包里提供了豐富的原子類,我們可以將其分為五個類別,這五個類別提供的方法基本上是相似的,并且每個類別都有若干原子類。

  • 對基本數(shù)據(jù)類型的變量值進(jìn)行原子更新;
  • 對對象變量的指向進(jìn)行原子更新;
  • 對數(shù)組里面的的元素進(jìn)行原子更新;
  • 原子化的對象屬性更新器;
  • 原子化的累加器。

007a32583fbf519469462fe61805eb4a.png

基本數(shù)據(jù)類型

AtomicBoolean、AtomicLong、AtomicInteger 這三個類提供了一些對基本數(shù)據(jù)類型的變量值進(jìn)行原子更新的方法。

這些類提供的方法是相似的,主要有(以 AtomicLong 為例):

// 原子化的 i++
long getAndIncrement()
// 原子化的 i--
long getAndDecrement()
// 原子化的 ++i
long incrementAndGet()
// 原子化的 --i
long decrementAndGet()
// 原子化的 i+=delta,返回值為+=前的i值
long getAndAdd(long delta)
// 原子化的 i+=delta,返回值為+=后的i值
long addAndGet(delta)
// CAS操作。如果寫回成功返回true,否則返回false
boolean compareAndSet(long expect, long update)
// 以下四個方法新值可以通過傳入函數(shù)式接口(func函數(shù))來計(jì)算
long getAndUpdate(LongUnaryOperator updateFunction)
long updateAndGet(LongUnaryOperator updateFunction)
long getAndAccumulate(long x, LongBinaryOperator accumulatorFunction)
long accumulateAndGet(long x, LongBinaryOperator accumulatorFunction)
// 演示 getAndUpdate() 方法的使用
public static void main(String[] args) {
    AtomicLong atomicLong = new AtomicLong(0);
    long result = atomicLong.getAndUpdate(new LongUnaryOperator() {
        @Override
        public long applyAsLong(long operand) {
            return operand + 1;
        }
    });
}

對象引用類型

AtomicReference、AtomicStampedReference、AtomicMarkableReference 這三個類提供了一些對對象變量的指向進(jìn)行原子更新的方法。如果需要對對象的屬性進(jìn)行原子更像,那么可以使用原子化的對象屬性更新器。

public class ClassName {
    AtomicReference<Employee> employeeAR = new AtomicReference<>(new Employee("小明"));
    public void methodName() {
        Employee oldVal = employeeAR.get();
        Employee newVal = new Employee(oldVal.getName());
        employeeAR.compareAndSet(oldVal, newVal);
    }
}

對象引用的原子化更新需要重點(diǎn)關(guān)注 ABA 問題。當(dāng)一個線程在進(jìn)行 CAS 操作時(shí),另一個線程可能會在此期間修改了同一個共享變量的值,然后又將其改回原來的值。這種情況下,CAS 操作就無法檢測到共享變量值的變化,從而導(dǎo)致 ABA 問題。如果我們僅僅在寫回?cái)?shù)據(jù)前判斷數(shù)值是 A,可能導(dǎo)致不合理的寫回操作。AtomicStampedReference 和 AtomicMarkableReference 這兩個原子類可以解決 ABA 問題。

  • AtomicStampedReference 通過為對象引用建立類似版本號(stamp)的方式,來解決 ABA 問題。
  • AtomicStampedReference 實(shí)現(xiàn)的 CAS 方法增加了版本號參數(shù)AtomicMarkableReference 的實(shí)現(xiàn)機(jī)制則更簡單,將版本號簡化成了一個 Boolean 值
boolean compareAndSet(V expectedReference, V newReference, 
                          int expectedStamp, int newStamp)
boolean compareAndSet(V expectedReference, V newReference,
                          boolean expectedMark, boolean newMark)

數(shù)組

AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray 這三個類提供了一些對數(shù)組里面的的元素進(jìn)行原子更新的方法。

public class ClassName {
    AtomicLongArray atomicLongArray = new AtomicLongArray(new long[]{0, 1});
    public void methodName() {
        int index = 0;
        long oldVal = atomicLongArray.get(index);
        long newVal = oldVal + 1;
        atomicLongArray.compareAndSet(index, oldVal, newVal);
    }
}

原子化的對象屬性更新器

原子化的對象屬性更新器有:AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicReferenceFieldUpdater。

這三個類提供了一些對對象的屬性進(jìn)行原子更新的方法。這些方法是利用反射機(jī)制實(shí)現(xiàn)的。

public class ClassName {
    AtomicIntegerFieldUpdater<Employee> fieldUpdater =
            AtomicIntegerFieldUpdater.newUpdater(Employee.class, "salary");
    Employee employee = new Employee("小明", 1000);
    public void methodName() {
        int oldVal = employee.getSalary();
        int newVal = oldVal + 1000;
        fieldUpdater.compareAndSet(employee, oldVal, newVal);
    }
}

需要注意的是:

  • 對象屬性的類型必須是基本數(shù)據(jù)類型,不能是基本數(shù)據(jù)類型對應(yīng)的包裝類。如果對象屬性的類型不是基本數(shù)據(jù)類型,newUpdater() 方法會拋出 IllegalArgumentException 運(yùn)行時(shí)異常。
  • 對象的屬性必須是 volatile 類型的,只有這樣才能保證可見性。如果對象的屬性不是 volatile 類型的,newUpdater() 方法會拋出 IllegalArgumentException 運(yùn)行時(shí)異常。
// AtomicIntegerFieldUpdater 類中的代碼
if (field.getType() != int.class) {
    throw new IllegalArgumentException("Must be integer type");
}
if (!Modifier.isVolatile(modifiers)) {
    throw new IllegalArgumentException("Must be volatile type");
}

原子化的累加器

原子化的累加器有:LongAdder、DoubleAdder、LongAccumulator、DoubleAccumulator。這四個類僅僅用來在多線程環(huán)境下,執(zhí)行累加操作。

相比原子化的基本數(shù)據(jù)類型,原子化的累加器的速度更快,但是它(原子化的累加器)不支持 compareAndSet() 方法。如果僅僅需要累加操作,使用原子化的累加器性能會更好。

原子化的累加器的本質(zhì)是空間換時(shí)間。

LongAdder 的使用示例如下所示:

public static void main(String[] args) {
    LongAdder adder = new LongAdder();
    // 初始化
    adder.add(1);
    // 累加
    for (int i = 0; i < 100; i++) {
        adder.increment();
    }
    long sum = adder.sum();
}

LongAccumulator 與 LongAdder 類似,但 LongAccumulator 提供了更加靈活的累加操作,可以自定義累加函數(shù)。

使用示例如下所示。在使用示例中,我們創(chuàng)建了一個 LongAccumulator 對象,初始值為1,累加函數(shù)為 (x, y) -> x * y,即每次累加都將之前的結(jié)果與新的值相乘。然后,我們累加了三個數(shù)值,最后輸出累加結(jié)果。由于累加函數(shù)是(x, y) -> x * y,所以最終的累加結(jié)果為1 * 5 * 10 * 20 = 1000。 

public static void main(String[] args) {
    LongAccumulator accumulator = new LongAccumulator(new LongBinaryOperator() {
        @Override
        public long applyAsLong(long left, long right) {
            return left * right;
        }
    }, 1);
    // 初始值為1,累加函數(shù)為(x, y) -> x * y
    accumulator.accumulate(5);
    accumulator.accumulate(10);
    accumulator.accumulate(20);
    // 累加結(jié)果為 1 * 5 * 10 * 20 = 1000
    long result = accumulator.get();
}

到此這篇關(guān)于Java的Atomic原子類的文章就介紹到這了,更多相關(guān)Java Atomic原子類內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java解析XML幾種方式小結(jié)

    java解析XML幾種方式小結(jié)

    本文給大家匯總了4種java解析XML的方法,結(jié)合具體的示例,非常的詳細(xì),有需要的小伙伴可以參考下
    2016-01-01
  • 利用Java獲取文件名、類名、方法名和行號的方法小結(jié)

    利用Java獲取文件名、類名、方法名和行號的方法小結(jié)

    這篇文章運(yùn)用實(shí)例代碼給大家介紹了利用Java怎樣獲取文件名、類名、方法名和行號,有需要的可以參考借鑒,下面一起來看看吧。
    2016-08-08
  • idea創(chuàng)建spring boot工程及配置文件(最新推薦)

    idea創(chuàng)建spring boot工程及配置文件(最新推薦)

    本文給大家介紹idea創(chuàng)建spring boot工程及配置文件,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2023-11-11
  • spring通過jdbc連接數(shù)據(jù)庫

    spring通過jdbc連接數(shù)據(jù)庫

    這篇文章主要為大家詳細(xì)介紹了spring通過jdbc連接數(shù)據(jù)庫的相關(guān)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-08-08
  • IDEA插件開發(fā)之環(huán)境搭建過程圖文詳解

    IDEA插件開發(fā)之環(huán)境搭建過程圖文詳解

    這篇文章主要介紹了IDEA插件開發(fā)之環(huán)境搭建過程,本文通過圖文并茂實(shí)例代碼相結(jié)合給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-05-05
  • 深入理解Java之HashMap源碼剖析

    深入理解Java之HashMap源碼剖析

    這篇文章主要介紹了深入理解Java之HashMap源碼剖析,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-02-02
  • java封裝全局異常處理深入詳解

    java封裝全局異常處理深入詳解

    這篇文章主要為大家介紹了java封裝全局異常處理的深入詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-09-09
  • MapStruct升級遇到的問題及解決方案

    MapStruct升級遇到的問題及解決方案

    MapStruct是一個用于生成類型安全,本文來介紹一下MapStruct升級遇到的問題及解決方案,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-12-12
  • Java如何對方法進(jìn)行調(diào)用詳解

    Java如何對方法進(jìn)行調(diào)用詳解

    今天給大家整理了Java如何對方法進(jìn)行調(diào)用,文中有非常詳細(xì)的介紹及代碼示例,對正在學(xué)習(xí)java的小伙伴們很有幫助,需要的朋友可以參考下
    2021-06-06
  • Redisson分布式鎖的源碼解讀分享

    Redisson分布式鎖的源碼解讀分享

    Redisson是一個在Redis的基礎(chǔ)上實(shí)現(xiàn)的Java駐內(nèi)存數(shù)據(jù)網(wǎng)格(In-Memory?Data?Grid)。Redisson有一樣功能是可重入的分布式鎖。本文來討論一下這個功能的特點(diǎn)以及源碼分析
    2022-11-11

最新評論