一、復習
Random類以及ThreadLocalRandom類原始碼決議
二、Java并發包中一些原子操作類的原始碼決議
1.常見類
例如AtomicLong,AtomicInteger,AtomicCharacter.....等這些操作類其內部實作都是通過CAS非阻塞演算法來實作, 因此我們只要弄懂一個其他就基本知曉了,因此本文講解AtomicLong類的實作原理 AtomicLong還有LongAdder,LongAccumulator等類是對AtomicLong特性的增強,我們后面再說
2.AtomicLong類
優點:使用CAS非阻塞演算法實作并發,比使用synchronized等鎖機制的非阻塞演算法,并發性要好很多, 下面來看一下它的原始碼,注意看注釋基本都解釋清楚了
package com.ruigege.AtomicOperationClass4;
import java.util.concurrent.atomic.AtomicLong;
import jdk.internal.misc.Unsafe;
import java.lang.Number;
public class AtomicLongTest extends Number implements java.io.Serializable{
private static final long serialVersionUID = 1927816293512124184L;
private static final Unsafe unsafe = Unsafe.getUnsafe();
private volatile long value;//用于放實際值的變數
private final long valueOffset;//value的偏移量
static {
try {
valueOffset = unsafe.objectFieldOffset(AtomicLong.class.getDeclaredField(value));
}catch(Exception e) {
throw new Error(e);
}
}
public AtomicLongTest(long initialValue) {
value = initialValue;
}
//下面的陳述句是用于判斷JVM是否支持Long型別的CAS
static final boolean VM_SUPPORTS_LONG_CAS = VMSupportsCS8();
private static native boolean VMSupportCS8();
/**
* 該方法使用CAS演算法用于累加
* @return
*/
public final long incrementAndGet() {
return unsafe.getAndAddLong(this, valueOffset, 1L) + 1L;
}
/**
* 我們來一起回顧一下Unsafe類中的成員方法getAndAddLong方法
* public final long getAndAddLong(Object obj,long offset,long addValue){
* long l;
* do{
* l = getLongvolatie(obj,offset);//獲取obj物件偏移量為offset的值
* }(!compareAndSwapLong(obj,offset,l,l+addValue));如與預期不相同,那么我們不斷地獲取l的值,如果
* //相同了,說明這個時候可以+addValue將得到的值賦值給l就可以了
* return l;最后回傳的是+addValue之前的值
* //我理解的CAS演算法,其實它的本質就是不斷回圈獲取一致的值,再進行更新,
* }
*/
/**
* 該方法使用CAS用于累減
* @return
*/
public final long decrementAndGet() {
return unsafe.getAndAddLong(this,valueOffset,-1L) -1L;
}
/**
* 下面這兩個方法,可以和上面的兩個方法作對比,都是累加,但是上面回傳是累加之后的值,下面是回傳累加之前的值
* @return
*/
public final long getAndIncrement() {
return unsafe.getAndAddLong(this, valueOffset, 1L);
}
public final long getAndDecrement() {
return unsafe.getAndAddLong(this,valueOffset,-1L);
}
/**
* 下面這個方法類似于Unsafe中的compareAndSwapLong方法
* @param expect
* @param update
* @return
*/
public final boolean compareAndSet(long expect,long update) {
return unsafe.compareAndSwapLong(this,valueOffset,expect,update);
}
}
上面的代碼是JDK8中的代碼,我們可以拿出一個方法getAndIncrement,來對比再JDK7中的實作原始碼
public final int getAndIncrement(){
while(true){
long temp = get();//這一行就是或者value的值
long newTemp = temp + 1;
if(compareAndSet(temp,newTemp){
//這里面的判斷是使用了該類里面測成員方法
return temp;
}
}
}
這個回圈的意義其實就是一個CAS操作,我們不斷回圈獲取value的值, 然后一致了,就開始設定,不一致的時候,就不斷的開始獲取,直到一致,JDK8其實不過是使用了Unsafe類作為工具類,來實作CAS操作, 在沒有原子類的時候,我們使用鎖synchronize機制來保證一致性,會大大降低并發效率;使用原子類,提高了效率,但是在大規模的并發下,這個類還是存在效率低的問題,因此引出今日主角
3.LongAdder類
atomicLong的困境以及如果優化:AtomicLong類的問題在于,在高并發的情況下,所有的執行緒都會區競爭同一個共享變數,并且根據CAS機制,最后只有一個執行緒能夠更新成功,這就導致了,其他執行緒為了獲取共享變數,會進入到無限回圈的自旋中;引入LongAdder類就是把一個共享變數分成為了多個共享變數,那么執行緒去競爭的時候,壓力會小一些,每個執行緒競爭到共享變數的可能性大大增加,

基本構成:LongAdder內部是由一個Cell陣列(需要初始化時才會創建陣列,沒有初始化時為null)和一個base變數,當創建該類實體以后,共享變數會變成多個Cell物件(共享變數被Cell類封裝了),然后在高并發下,執行緒可以競爭的共享變數(Cell實體)就變多了,并且一個執行緒如果沒有獲取到Cell實體,并不會進入到自旋狀態下,而是去競爭其他Cell;LongAdder實體的值,就是個各個Cell值累加,在加上base變數的值,該類其內部陣列是一個延遲初始化原子性更新陣列,屬于惰性加載;
當一開始判斷Cell陣列時null時,所有累加操作都是在base變數上的,保持Cell陣列的大小是2的N次方,在初始化陣列的時候,大小為2,里面的元素是Cell實體,這個是一個Atomic改進類,用于解決偽共享問題
變數加載時的提升原理:對于大多數孤立的多個資源子操作進行位元組填充是浪費,但是 LongAdder實體的陣列可以是記憶體連續,因此我們需要添加個@sun.misc.Contended注解對Cell類進行填充,這樣按行加載記憶體機制就得到優化,提升性能,
詳細原理我們下次再說
三、原始碼:
所在包:com.ruigege.AtomicOperationClass4 https://github.com/ruigege66/ConcurrentJavaCSDN:https://blog.csdn.net/weixin_44630050 博客園:https://www.cnblogs.com/ruigege0000/ 歡迎關注微信公眾號:傅里葉變換,個人賬號,僅用于技術交流 
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/237455.html
標籤:其他
上一篇:MyBatisPlus-常用注解
