亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java的Atomic原子類(lèi)詳解

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

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

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

007a32583fbf519469462fe61805eb4a.png

基本數(shù)據(jù)類(lèi)型

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

這些類(lèi)提供的方法是相似的,主要有(以 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操作。如果寫(xiě)回成功返回true,否則返回false
boolean compareAndSet(long expect, long update)
// 以下四個(gè)方法新值可以通過(guò)傳入函數(shù)式接口(func函數(shù))來(lái)計(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;
        }
    });
}

對(duì)象引用類(lèi)型

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

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);
    }
}

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

  • AtomicStampedReference 通過(guò)為對(duì)象引用建立類(lèi)似版本號(hào)(stamp)的方式,來(lái)解決 ABA 問(wèn)題。
  • AtomicStampedReference 實(shí)現(xiàn)的 CAS 方法增加了版本號(hào)參數(shù)AtomicMarkableReference 的實(shí)現(xiàn)機(jī)制則更簡(jiǎn)單,將版本號(hào)簡(jiǎn)化成了一個(gè) 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 這三個(gè)類(lèi)提供了一些對(duì)數(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);
    }
}

原子化的對(duì)象屬性更新器

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

這三個(gè)類(lèi)提供了一些對(duì)對(duì)象的屬性進(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);
    }
}

需要注意的是:

  • 對(duì)象屬性的類(lèi)型必須是基本數(shù)據(jù)類(lèi)型,不能是基本數(shù)據(jù)類(lèi)型對(duì)應(yīng)的包裝類(lèi)。如果對(duì)象屬性的類(lèi)型不是基本數(shù)據(jù)類(lèi)型,newUpdater() 方法會(huì)拋出 IllegalArgumentException 運(yùn)行時(shí)異常。
  • 對(duì)象的屬性必須是 volatile 類(lèi)型的,只有這樣才能保證可見(jiàn)性。如果對(duì)象的屬性不是 volatile 類(lèi)型的,newUpdater() 方法會(huì)拋出 IllegalArgumentException 運(yùn)行時(shí)異常。
// AtomicIntegerFieldUpdater 類(lèi)中的代碼
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。這四個(gè)類(lèi)僅僅用來(lái)在多線程環(huán)境下,執(zhí)行累加操作。

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

原子化的累加器的本質(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 類(lèi)似,但 LongAccumulator 提供了更加靈活的累加操作,可以自定義累加函數(shù)。

使用示例如下所示。在使用示例中,我們創(chuàng)建了一個(gè) LongAccumulator 對(duì)象,初始值為1,累加函數(shù)為 (x, y) -> x * y,即每次累加都將之前的結(jié)果與新的值相乘。然后,我們累加了三個(gè)數(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原子類(lèi)的文章就介紹到這了,更多相關(guān)Java Atomic原子類(lèi)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

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

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

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

    利用Java獲取文件名、類(lèi)名、方法名和行號(hào)的方法小結(jié)

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

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

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

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

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

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

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

    深入理解Java之HashMap源碼剖析

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

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

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

    MapStruct升級(jí)遇到的問(wèn)題及解決方案

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

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

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

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

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

最新評(píng)論