JUC 4 0 原子類 介紹及基本使用

2021-10-05 05:07:02 字數 3252 閱讀 5294

在併發程式設計中,原子類也是經常使用的乙個工具,利用原子類,可以把一些操作變成乙個原子操作,在多執行緒的情況下不需要加鎖也可以保證執行緒安全

原子類的作用跟鎖是類似的,都是為了保證在併發環境下的執行緒安全,原子類相比於鎖,有一定的優勢

鎖的粒度更細: 原子類可以把競爭範圍縮小到變數級別,通常我們手動加鎖的粒度都會大於原子變數的粒度

效率更高: 一般情況下,原子類的效率會比使用鎖的效率高,除了高度競爭的情況

常用的原子類有以下幾種

基本原子型別

作用: 對基本型別的操作變為原子操作

原子陣列型別

作用: 對陣列的操作為原子操作

引用型別原子類

作用: 引用型別針對的都是物件

公升級型別原子類

累加器作用: 高效累加操作

atmoicinteger為例,了解一下基本的用法,以及常用的方法

public class atomicintegertest 

}

原子陣列

原子陣列就是陣列中每個屬性都是原子的,下面**執行100次的加減操作,最後array中的每個屬性結果都為0

public class atomicarraydemo 

for (int i =0;i<100;i++)

//判斷加減之後值是否非零

for (int i=0;iatomicreference

這個類的作用,和atmoicinteger本質上沒有卻別,atmoicinteger是讓乙個整形變數保證原子性,atomicreference可以讓乙個物件保證原子性 ,不過乙個物件是可以包含很多屬性的

在之前鎖的章節,有乙個自旋鎖的案例,已經用到這個型別了, **再貼過來回顧一下

public class spinlock

}private void unlock()

}

這裡就用到了乙個原子類的compareandset這個cas操作,對比並賦值

公升級型別原子類,功能是把乙個普通的變數公升級為原子類,主要的使用場景是當乙個普通變數偶爾需要原子操作的時候使用

atomicintegerfieldupdater為例,就是將乙個整形公升級為原子整形

這裡就會把屬性tom這個物件的score變為原子操作 。

注意點:變數必須是可見的,也就是必須使用volatile修飾;不能使用static修飾;

在高併發下longadder的效率比atomiclong要高 ,以空間換時間。

使用方式就是new longadder();然後呼叫add()方法就可以了

那麼為什麼atomiclong的效能不如longadder呢?

atomiclong每次執行修改操作,都要flush到主存 和refresh其他執行緒的工作記憶體,在高併發的情況下效率就很低了,而longadder每個執行緒各自維護自己的變數以及值,用來在自己的執行緒內計算,等最後要獲取值的時候,把所有執行緒的和在加起來就是總和

longadder 帶來的設計和原理

longadder引入了分段累加的概念,內部有乙個base變數和乙個cell陣列參與計算;當競爭不激烈的時候,直接累加到base變數,競爭激烈的時候,各個執行緒分散累加到自己的槽cell[i]中。

對比 atomiclong

在低爭用下,atomiclonglongadder這兩個類具有相似的特徵,但是在競爭激烈的情況下,longadder的預期吞吐量要高得多,但要消耗更多的空間。並且最後的求和不是十分十分的精確,比如,當最後的求和加到一半的時候,cell陣列的前半部分又有值改變了,就會影響最終結果。

public long sum() 

}return sum;

}

longadder適合的場景是統計求和計數的場景,而且longadder基本只提供了 add 方法,而atomiclong還具有cas方法

accumulator是乙個更加靈活的累加器,使用方式上跟上面的longadder是有些不同的,如下

longaccumulator accumulator = new longaccumulator(long::sum, 0);

longaccumulator accumulator1 = new longaccumulator((x, y) -> x + y, 0);

accumulator1.accumulate(1);

// 獲取後清空

accumulator1.getthenreset();

**中的accumulatoraccumulator1作用都是一樣的, 就是lambda的兩種寫法,下面這個看著更直觀一點

longaccumulator需要兩個引數,第乙個是longbinaryoperator的實現它是乙個函式式介面, 然後傳參的時候傳具體的實現就可以,第二個引數 0 就是 x 的初始值

上面**中,剛初始化的時候 x 就是 0 ,然後第一次累加的時候會把x的值給y,然後再把傳進來的x跟y做累加,結果賦值給 y

當然這個表示式不一定就是累加,也可以做自己的實現,所以這個比上面的longadder要更加靈活

適用場景

JUC中的原子類總結

atomic原子類介紹 atomic 是指乙個操作是不可中斷的。即使是在多個執行緒一起執行的時候,乙個操作一旦開始,就不會被其他執行緒干擾。分類 根據操作的資料型別,可以分為4類 基本資料型別 陣列型別 使用原子的方式更新陣列裡的某個元素 引用型別 物件的屬性修改型別 通過乙個簡單例子帶大家看一下基...

JUC包下的原子類的實現方法

class accountsafe implements account override public integer getbalance override public void withdraw integer amount 可以簡化為下面的方法 balance.addandget 1 am...

Java多執行緒系列 「JUC原子類」01之 框架

根據修改的資料型別,可以將juc包中的原子操作類可以分為4類。1.基本型別 atomicinteger,atomiclong,atomicboolean 2.陣列型別 atomicintegerarray,atomiclongarray,atomicreferencearray 3.引用型別 ato...