在併發程式設計中,原子類也是經常使用的乙個工具,利用原子類,可以把一些操作變成乙個原子操作,在多執行緒的情況下不需要加鎖也可以保證執行緒安全
原子類的作用跟鎖是類似的,都是為了保證在併發環境下的執行緒安全,原子類相比於鎖,有一定的優勢
鎖的粒度更細: 原子類可以把競爭範圍縮小到變數級別,通常我們手動加鎖的粒度都會大於原子變數的粒度
效率更高: 一般情況下,原子類的效率會比使用鎖的效率高,除了高度競爭的情況
常用的原子類有以下幾種
基本原子型別
作用: 對基本型別的操作變為原子操作
原子陣列型別
作用: 對陣列的操作為原子操作
引用型別原子類
作用: 引用型別針對的都是物件
公升級型別原子類
累加器作用: 高效累加操作
以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
在低爭用下,atomiclong
和longadder
這兩個類具有相似的特徵,但是在競爭激烈的情況下,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();
**中的accumulator
和accumulator1
作用都是一樣的, 就是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...