Java多線程編程三 原子類

Java的原子類

JUC并發(fā)包中提供了一系列原子性操作類,這些類都是使用非阻塞算法 CAS 實(shí)現(xiàn)的,比使用鎖性能有提升。具體實(shí)現(xiàn)大致相同。

原子更新基本類型

AtomicBoolean、AtomicInteger、AtomicLong

關(guān)鍵實(shí)現(xiàn)代碼

public class AtomicLong extends Number implements java.io.Serializable {
    private static final long serialVersionUID = 1927816293512124184L;
    private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
    private static final long VALUE = U.objectFieldOffset(AtomicLong.class, "value");

    private volatile long value;
    ···
}

核心方法

public final boolean compareAndSet(long expectedValue, long newValue) {
    return U.compareAndSetLong(this, VALUE, expectedValue, newValue);
}

public final long getAndIncrement() {
    return U.getAndAddLong(this, VALUE, 1L);
}

public final long getAndDecrement() {
    return U.getAndAddLong(this, VALUE, -1L);
}
public final long incrementAndGet() {
    return U.getAndAddLong(this, VALUE, 1L) + 1L;
}


public final long decrementAndGet() {
    return U.getAndAddLong(this, VALUE, -1L) - 1L;
}

原子更新數(shù)組類型

AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray

調(diào)用構(gòu)造方法時(shí),會(huì)對(duì)參數(shù)數(shù)組拷貝一次。

原子更新引用類型

AtomicReference (存在ABA問(wèn)題)

AtomicStampedReference(帶有時(shí)間戳,處理ABA問(wèn)題)

AtomicMarkableReference(通過(guò)添加帶有對(duì)象是否被修改的boolean值,處理ABA問(wèn)題)

例子:

public class HelloWorld {
    public static void main(String[] args) {
        User user1 = new User();
        user1.setAge(14);
        user1.setName("hello");
        AtomicReference<User> userAtomicReference = new AtomicReference<>(user1);
        User user2 = new User();
        user2.setName("world");
        user2.setAge(34);
        userAtomicReference.compareAndSet(user1,user2);
        System.out.println(userAtomicReference.get());
    }

}
class User{
    private String name;
    private Integer age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
atomiclass1.png

原子更新類字段類型

AtomicIntegerFieldUpdater AtomicLongFieldUpdater AtomicReferenceFieldUpdater

優(yōu)化后的原子操作類

LongAdderLongAccumulator、DoubleAdder、DoubleAccumulator

AtomicLong 類使用 CAS 提供非阻塞原子操作,比起鎖已經(jīng)優(yōu)化了很多,但使用 AtomicLong 在多線程環(huán)境下會(huì)造成線程不斷自旋嘗試(源碼使用無(wú)限循環(huán)),浪費(fèi) CPU 資源。為了解決此問(wèn)題,LongAdder 類在內(nèi)部維護(hù)的多個(gè) Cell 元素來(lái)分擔(dān)對(duì)單個(gè)變量進(jìn)行爭(zhēng)奪的開(kāi)銷。、

LongAdder 類繼承自 Striped64 類,實(shí)現(xiàn)序列化。Striped64內(nèi)部維護(hù)著三個(gè)變量

    volatile long base;//初始值
    volatile int cellsBusy;//用來(lái)實(shí)現(xiàn)自旋鎖,狀態(tài)值 0 與 1 
    volatile Cell[] cells;//原子可見(jiàn)的Cell元素

底層通過(guò) CAS 算法實(shí)現(xiàn)非阻塞原子操作

@sun.misc.Contented//避免Cell數(shù)組的偽分享出現(xiàn),導(dǎo)致降低并發(fā)訪問(wèn)的性能
    static final class Cell{
        volatile long value;
        Cell(long x){
            value = x;
        }
        final boolean cas(long cmp,long val){
            return UNSAFE.compareAndSwapLong(this,valueOffest,cmp,val);//使用Unsafe類實(shí)現(xiàn)對(duì)Cell元素操作的原子性
        }
    }

在 LongAdder 類中維護(hù)的變量 cells 采用延遲初始化策略。cells 的元素通過(guò) cas 函數(shù)的 CAS 操作達(dá)到原子性更新。

    public long sum();//返回當(dāng)前的值,內(nèi)部所有 cell 和 base 的和,相加時(shí)未使用鎖,返回值不精確,此時(shí)可能有 cell 被修改。多線程有問(wèn)題。+
    public void reset();//重置,base 置0 ,若 cells 的元素有值則置0.
    public long sumThenReset(); //累加后置0,多線程有問(wèn)題。
    public long longValue(); //等價(jià)與sum();

LongAccumulator(JDK8)

LongAdder 類是 LongAccumulator 的一個(gè)特例,LongAccumulator 更加強(qiáng)大。

構(gòu)造方法:

//當(dāng) function 為null時(shí),雙目運(yùn)算器為默認(rèn)的加法運(yùn)算器
public LongAccumulator(LongBinaryOperator function, long identify){
    this.function = function;
    base = this.identify = identify;//可以提供非0的初始值
}
//LongBinaryOperator雙目運(yùn)算器接口
public interface LongBinaryOperator{
    long applyAsLong(long left, long right);
}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容