日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Jdk1.8 JUC源码增量解析(1)-atomic-Striped64

發布時間:2023/12/3 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Jdk1.8 JUC源码增量解析(1)-atomic-Striped64 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉載自??Jdk1.8 JUC源碼增量解析(1)-atomic-Striped64

功能簡介:
  • Striped64是jdk1.8提供的用于支持如Long累加器,Double累加器這樣機制的基礎類。
  • Striped64的設計核心思路就是通過內部的分散計算來避免競爭(比如多線程CAS操作時的競爭)。
  • Striped64內部包含一個基礎值和一個單元哈希表。沒有競爭的情況下,要累加的數會累加到這個基礎值上;如果有競爭的話,會將要累加的數累加到單元哈希表中的某個單元里面。所以整個Striped64的值包括基礎值和單元哈希表中所有單元的值的總和。
源碼分析:
  • 先看一下內部結構:
  • /**?
  • ?*?存放Cell的hash表,大小為2的冪。?
  • ?*/??
  • transient?volatile?Cell[]?cells;??
  • /**?
  • ?*?基礎值,沒有競爭時會使用(更新)這個值,同時做為初始化競爭失敗的回退方案。?
  • ?*?原子更新。?
  • ?*/??
  • transient?volatile?long?base;??
  • /**?
  • ?*?自旋鎖,通過CAS操作加鎖,用于保護創建或者擴展Cell表。?
  • ?*/??
  • transient?volatile?int?cellsBusy;??
  • ?

    ? ? ? ?看下Cell的內部結構:

  • @sun.misc.Contended???
  • static?final?class?Cell?{??
  • ????volatile?long?value;??
  • ????Cell(long?x)?{?value?=?x;?}??
  • ????final?boolean?cas(long?cmp,?long?val)?{??
  • ????????return?UNSAFE.compareAndSwapLong(this,?valueOffset,?cmp,?val);??
  • ????}??
  • ????//?Unsafe?mechanics??
  • ????private?static?final?sun.misc.Unsafe?UNSAFE;??
  • ????private?static?final?long?valueOffset;??
  • ????static?{??
  • ????????try?{??
  • ????????????UNSAFE?=?sun.misc.Unsafe.getUnsafe();??
  • ????????????Class<?>?ak?=?Cell.class;??
  • ????????????valueOffset?=?UNSAFE.objectFieldOffset??
  • ????????????????(ak.getDeclaredField("value"));??
  • ????????}?catch?(Exception?e)?{??
  • ????????????throw?new?Error(e);??
  • ????????}??
  • ????}??
  • }??
  • ? ? ?Cell內部保存了一個volatile修飾的long型域,同時提供了原子操作,看起來像一個原子量。? ? ? ?注意到Cell類被一個Contended注解修飾,Contended的作用是對Cell做緩存行填充,避免偽共享。
    • Striped64主要提供了longAccumulate和doubleAccumulate方法來支持子類,先看下longAccumulate:
  • static?final?int?NCPU?=?Runtime.getRuntime().availableProcessors();??
  • final?void?longAccumulate(long?x,?LongBinaryOperator?fn,??
  • ??????????????????????????boolean?wasUncontended)?{??
  • ????int?h;??
  • ????//獲取當前線程的probe值作為hash值。??
  • ????if?((h?=?getProbe())?==?0)?{??
  • ????????//如果probe值為0,強制初始化當前線程的probe值,這次初始化的probe值不會為0。??
  • ????????ThreadLocalRandom.current();???
  • ????????//再次獲取probe值作為hash值。??
  • ????????h?=?getProbe();??
  • ????????//這次相當于再次計算了hash,所以設置未競爭標記為true。??
  • ????????wasUncontended?=?true;??
  • ????}??
  • ????boolean?collide?=?false;??
  • ????for?(;;)?{??
  • ????????Cell[]?as;?Cell?a;?int?n;?long?v;??
  • ????????if?((as?=?cells)?!=?null?&&?(n?=?as.length)?>?0)?{??
  • ????????????//通過h從cell表中選定一個cell位置。??
  • ????????????if?((a?=?as[(n?-?1)?&?h])?==?null)?{??
  • ????????????????//如果當前位置沒有cell,嘗試新建一個。??
  • ????????????????if?(cellsBusy?==?0)?{??
  • ????????????????????//創建一個Cell。?????????
  • ????????????????????Cell?r?=?new?Cell(x);???
  • ????????????????????//嘗試或者cellsBusy鎖。??
  • ????????????????????if?(cellsBusy?==?0?&&?casCellsBusy())?{??
  • ????????????????????????boolean?created?=?false;??
  • ????????????????????????try?{?????????????????
  • ????????????????????????????Cell[]?rs;?int?m,?j;??
  • ????????????????????????????//在獲取鎖的情況下再次檢測一下。??
  • ????????????????????????????if?((rs?=?cells)?!=?null?&&??
  • ????????????????????????????????(m?=?rs.length)?>?0?&&??
  • ????????????????????????????????rs[j?=?(m?-?1)?&?h]?==?null)?{??
  • ????????????????????????????????//設置新建的cell到指定位置。??
  • ????????????????????????????????rs[j]?=?r;??
  • ????????????????????????????????//創建標記設置為true。??
  • ????????????????????????????????created?=?true;??
  • ????????????????????????????}??
  • ????????????????????????}?finally?{??
  • ????????????????????????????//釋放cellsBusy鎖。??
  • ????????????????????????????cellsBusy?=?0;??
  • ????????????????????????}??
  • ????????????????????????if?(created)??
  • ????????????????????????????//如果創建成功,直接跳出循環,退出方法。??
  • ????????????????????????????break;??
  • ????????????????????????//說明上面指定的cell的位置上有cell了,繼續嘗試。??
  • ????????????????????????continue;????
  • ????????????????????}??
  • ????????????????}??
  • ????????????????//走到這里說明獲取cellsBusy鎖失敗。??
  • ????????????????collide?=?false;??
  • ????????????}??
  • ????????????//以下條件說明上面通過h選定的cell表的位置上有Cell,就是a。??
  • ????????????else?if?(!wasUncontended)???????//?CAS?already?known?to?fail??
  • ????????????????//如果之前的CAS失敗,說明已經發生競爭,??
  • ????????????????//這里會設置未競爭標志位true,然后再次算一個probe值,然后重試。??
  • ????????????????wasUncontended?=?true;??????//?Continue?after?rehash??
  • ????????????//這里嘗試將x值加到a的value上。??
  • ????????????else?if?(a.cas(v?=?a.value,?((fn?==?null)???v?+?x?:??
  • ?????????????????????????????????????????fn.applyAsLong(v,?x))))??
  • ????????????????//如果嘗試成功,跳出循環,方法退出。??
  • ????????????????break;??
  • ????????????else?if?(n?>=?NCPU?||?cells?!=?as)??
  • ????????????????//如果cell表的size已經最大,或者cell表已經發生變化(as是一個過時的)。??
  • ????????????????collide?=?false;?????????????
  • ????????????else?if?(!collide)??
  • ????????????????//設置沖突標志,表示發生了沖突,重試。??
  • ????????????????collide?=?true;??
  • ????????????//嘗試獲取cellsBusy鎖。??
  • ????????????else?if?(cellsBusy?==?0?&&?casCellsBusy())?{??
  • ????????????????try?{??
  • ????????????????????//檢測as是否過時。??
  • ????????????????????if?(cells?==?as)?{????????
  • ????????????????????????//給cell表擴容。??
  • ????????????????????????Cell[]?rs?=?new?Cell[n?<<?1];??
  • ????????????????????????for?(int?i?=?0;?i?<?n;?++i)??
  • ????????????????????????????rs[i]?=?as[i];??
  • ????????????????????????cells?=?rs;??
  • ????????????????????}??
  • ????????????????}?finally?{??
  • ????????????????????//釋放cellsBusy鎖。??
  • ????????????????????cellsBusy?=?0;??
  • ????????????????}??
  • ????????????????collide?=?false;??
  • ????????????????//擴容cell表后,再次重試。??
  • ????????????????continue;????????????????????
  • ????????????}??
  • ????????????//算出下一個hash值。??
  • ????????????h?=?advanceProbe(h);??
  • ????????}??
  • ????????//如果cell表還未創建,先嘗試獲取cellsBusy鎖。??
  • ????????else?if?(cellsBusy?==?0?&&?cells?==?as?&&?casCellsBusy())?{??
  • ????????????boolean?init?=?false;??
  • ????????????try?{????????????????????????????
  • ????????????????if?(cells?==?as)?{??
  • ????????????????????//初始化cell表,初始容量為2。??
  • ????????????????????Cell[]?rs?=?new?Cell[2];??
  • ????????????????????rs[h?&?1]?=?new?Cell(x);??
  • ????????????????????cells?=?rs;??
  • ????????????????????init?=?true;??
  • ????????????????}??
  • ????????????}?finally?{??
  • ????????????????//釋放cellsBusy鎖。??
  • ????????????????cellsBusy?=?0;??
  • ????????????}??
  • ????????????if?(init)??
  • ????????????????//初始化cell表成功后,退出方法。??
  • ????????????????break;??
  • ????????}??
  • ????????//如果創建cell表由于競爭導致失敗,嘗試將x累加到base上。??
  • ????????else?if?(casBase(v?=?base,?((fn?==?null)???v?+?x?:??
  • ????????????????????????????????????fn.applyAsLong(v,?x))))??
  • ????????????break;????????????????????????????
  • ????}??
  • }??
  • 說明一下這個方法,方法的作用是將給定的值x累加到當前值(Striped64本身)上,x值為正就是加、為負就是減。方法流程細節:? ? ? ?首先,方法內部首先會算一個hash值,用來確定cell數組的下標。hash值初始源于當前Thread中的threadLocalRandomProbe域,如果hash值初始后為0,會初始化一下當前線程的threadLocalRandomProbe值,然后再次賦給hash值。注意方法傳入第三個參數wasUncontended表示調用方法之前是否未發生競爭,加入前面走了初始化threadLocalRandomProbe的過程,就會將wasUncontended設置為true。? ? ? ?接下來,方法進入主循環。? ? ? ?1.先判斷Cell表是否創建。? ? ? ?1.1.如果Cell表未創建,嘗試獲取cellsBusy鎖。? ? ? ?1.1.1.如果獲取cellsBusy鎖成功,會創建一個size為2的Cell表作為初始cell表,然后新建一個保存給定x的Cell實例,然后根據hash值設置到Cell表對應的位置上;? ? ? ?1.1.2.如果獲取cellsBusy鎖失敗,會嘗試將x累加到base上,失敗重試。? ? ? ?1.2.如果Cell表已經創建,通過hash值算出一個Cell表中的位置,然后獲取這個位置上的Cell,稱為a。? ? ? ?1.2.1.如果a為null,嘗試獲取cellsBusy鎖。? ? ? ?1.2.1.1.如果獲取cellsBusy成功,創建一個新的Cell,然后賦值給a,方法退出。(過程中需要多次檢測沖突)? ? ? ?1.2.1.2.如果獲取cellsBusy失敗,會將collide設置為false(實際上是表示發生了沖突),然后重試。? ? ? ?1.2.2.如果a不為null。? ? ? ?1.2.2.1.如果wasUncontended為false,說明之前發生過CAS競爭失敗,設置wasUncontended為true,重新計算hash值,重試;如果wasUncontended為true,繼續嘗試下面過程。? ? ? ?1.2.2.2.嘗試通過CAS方式將x累加到a的value上,如果嘗試成功,方法退出;如果嘗試失敗,繼續嘗試下面過程。? ? ? ?1.2.2.3.如果當前Cell表的大小以及達到最大值(當前處理器核數),或者Cell表發生了變化(競爭導致過時),那么會設置collide為false,重新計算hash值,然后重試;否則,繼續嘗試下面過程。? ? ? ?1.2.2.4.如果collide為false,說明之前發生過沖突,將collide設置為true,重新計算hash值,然后重試;否則,繼續嘗試下面過程。? ? ? ?1.2.2.5.嘗試獲取cellsBusy,如果成功,擴展Cell表,并將collide設置為false,然后重試;否則,重新計算hash值,然后重試;

    ? ? ? ?看下longAccumulate中使用到的一些方法:

  • final?boolean?casBase(long?cmp,?long?val)?{??
  • ????return?UNSAFE.compareAndSwapLong(this,?BASE,?cmp,?val);??
  • }??
  • ??
  • final?boolean?casCellsBusy()?{??
  • ????return?UNSAFE.compareAndSwapInt(this,?CELLSBUSY,?0,?1);??
  • }??
  • ??
  • static?final?int?getProbe()?{??
  • ????return?UNSAFE.getInt(Thread.currentThread(),?PROBE);??
  • }??
  • ??
  • //計算下一個隨機值作為hash值,使用xorshift算法。??
  • static?final?int?advanceProbe(int?probe)?{??
  • ????probe?^=?probe?<<?13;??
  • ????probe?^=?probe?>>>?17;??
  • ????probe?^=?probe?<<?5;??
  • ????//設置到當前線程的threadLocalRandomProbe域。??
  • ????UNSAFE.putInt(Thread.currentThread(),?PROBE,?probe);??
  • ????return?probe;??
  • }??
  • ??

    • 再看下doubleAccumulate:
  • final?void?doubleAccumulate(double?x,?DoubleBinaryOperator?fn,??
  • ????????????????????????????boolean?wasUncontended)?{??
  • ????int?h;??
  • ????if?((h?=?getProbe())?==?0)?{??
  • ????????ThreadLocalRandom.current();?//?force?initialization??
  • ????????h?=?getProbe();??
  • ????????wasUncontended?=?true;??
  • ????}??
  • ????boolean?collide?=?false;????????????????//?True?if?last?slot?nonempty??
  • ????for?(;;)?{??
  • ????????Cell[]?as;?Cell?a;?int?n;?long?v;??
  • ????????if?((as?=?cells)?!=?null?&&?(n?=?as.length)?>?0)?{??
  • ????????????if?((a?=?as[(n?-?1)?&?h])?==?null)?{??
  • ????????????????if?(cellsBusy?==?0)?{???????//?Try?to?attach?new?Cell??
  • ????????????????????Cell?r?=?new?Cell(Double.doubleToRawLongBits(x));??
  • ????????????????????if?(cellsBusy?==?0?&&?casCellsBusy())?{??
  • ????????????????????????boolean?created?=?false;??
  • ????????????????????????try?{???????????????//?Recheck?under?lock??
  • ????????????????????????????Cell[]?rs;?int?m,?j;??
  • ????????????????????????????if?((rs?=?cells)?!=?null?&&??
  • ????????????????????????????????(m?=?rs.length)?>?0?&&??
  • ????????????????????????????????rs[j?=?(m?-?1)?&?h]?==?null)?{??
  • ????????????????????????????????rs[j]?=?r;??
  • ????????????????????????????????created?=?true;??
  • ????????????????????????????}??
  • ????????????????????????}?finally?{??
  • ????????????????????????????cellsBusy?=?0;??
  • ????????????????????????}??
  • ????????????????????????if?(created)??
  • ????????????????????????????break;??
  • ????????????????????????continue;???????????//?Slot?is?now?non-empty??
  • ????????????????????}??
  • ????????????????}??
  • ????????????????collide?=?false;??
  • ????????????}??
  • ????????????else?if?(!wasUncontended)???????//?CAS?already?known?to?fail??
  • ????????????????wasUncontended?=?true;??????//?Continue?after?rehash??
  • ????????????else?if?(a.cas(v?=?a.value,??
  • ???????????????????????????((fn?==?null)????
  • ????????????????????????????Double.doubleToRawLongBits??
  • ????????????????????????????(Double.longBitsToDouble(v)?+?x)?:??
  • ????????????????????????????Double.doubleToRawLongBits??
  • ????????????????????????????(fn.applyAsDouble??
  • ?????????????????????????????(Double.longBitsToDouble(v),?x)))))??
  • ????????????????break;??
  • ????????????else?if?(n?>=?NCPU?||?cells?!=?as)??
  • ????????????????collide?=?false;????????????//?At?max?size?or?stale??
  • ????????????else?if?(!collide)??
  • ????????????????collide?=?true;??
  • ????????????else?if?(cellsBusy?==?0?&&?casCellsBusy())?{??
  • ????????????????try?{??
  • ????????????????????if?(cells?==?as)?{??????//?Expand?table?unless?stale??
  • ????????????????????????Cell[]?rs?=?new?Cell[n?<<?1];??
  • ????????????????????????for?(int?i?=?0;?i?<?n;?++i)??
  • ????????????????????????????rs[i]?=?as[i];??
  • ????????????????????????cells?=?rs;??
  • ????????????????????}??
  • ????????????????}?finally?{??
  • ????????????????????cellsBusy?=?0;??
  • ????????????????}??
  • ????????????????collide?=?false;??
  • ????????????????continue;???????????????????//?Retry?with?expanded?table??
  • ????????????}??
  • ????????????h?=?advanceProbe(h);??
  • ????????}??
  • ????????else?if?(cellsBusy?==?0?&&?cells?==?as?&&?casCellsBusy())?{??
  • ????????????boolean?init?=?false;??
  • ????????????try?{???????????????????????????//?Initialize?table??
  • ????????????????if?(cells?==?as)?{??
  • ????????????????????Cell[]?rs?=?new?Cell[2];??
  • ????????????????????rs[h?&?1]?=?new?Cell(Double.doubleToRawLongBits(x));??
  • ????????????????????cells?=?rs;??
  • ????????????????????init?=?true;??
  • ????????????????}??
  • ????????????}?finally?{??
  • ????????????????cellsBusy?=?0;??
  • ????????????}??
  • ????????????if?(init)??
  • ????????????????break;??
  • ????????}??
  • ????????else?if?(casBase(v?=?base,??
  • ?????????????????????????((fn?==?null)????
  • ??????????????????????????Double.doubleToRawLongBits??
  • ??????????????????????????(Double.longBitsToDouble(v)?+?x)?:??
  • ??????????????????????????Double.doubleToRawLongBits??
  • ??????????????????????????(fn.applyAsDouble??
  • ???????????????????????????(Double.longBitsToDouble(v),?x)))))??
  • ????????????break;??????????????????????????//?Fall?back?on?using?base??
  • ????}??
  • }??
  • doubleAccumulate方法是針對double值做累加的,邏輯和longAccumulate一致。但由于Cell內部用long保存數據,所以在累加的時候會利用Double的doubleToRawLongBits和longBitsToDouble方法做double和longBits形式的double之間的轉換。Striped64的代碼解析完畢!參考資料:http://mail.openjdk.java.net/pipermail/hotspot-dev/2012-November/007309.html
    創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

    總結

    以上是生活随笔為你收集整理的Jdk1.8 JUC源码增量解析(1)-atomic-Striped64的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。