単純に感じて、少し上の記事、BoundedConcurrentHashMapを書くhttps://www.cnblogs.com/qiaoyutao/p/10903813.htmlあまり使用し、今日について書くことは、理解のソースConcurrentHashMapのいくつかの一般的な方法に焦点を当てて
注:この記事は純粋に個人的な理解で、読者は、参考値です。
コンストラクタ初めて目
公共のConcurrentHashMapの(地図<?延び K ,? 延び V> M){ この .sizeCtl = DEFAULT_CAPACITY; // テーブルの長さをデフォルト設定として= 16 DEFAULT_CAPCITY; のputAll(M); //がマップに渡されたメソッドを呼び出しますスレッドセーフなハッシュテーブルとして構成され、以下にのputAll源です }
公共 ボイドのputAll(地図<?延び K ,? 延び V> M){ tryPresize(m.sizeを()); //着信sizeCtlマップテーブルのサイズに応じて、このテーブルマップの大きさを調整し、作成しようとm.size長ノード<K、V>メンバ変数テーブルに[]配列。 用(のMap.Entryの<?延び K、?延び V> E:m.entrySet())アレイの上方に配置されコレクションを//ノード。以下は、方法PutValある PutVal(e.getKey()、e.getValue()、falseに;) }
最終的な V PutVal(キーK、V値、ブールonlyIfAbsent){ IF(キー==のヌル ||値== nullの)スロー 新しい新しいのNullPointerException(); //キーまたは値を許可していませんがnullの場合、 int型のハッシュ= スプレッド(key.hashCode ()); //再鍵ハッシュに INT BinCount = 0 ; //ノード要素の合計数を計算するために使用される、追加の容量が必要、または赤黒木に変換されているかどうかを決定するために するため(ノード<K、 V> []タブ= テーブル;;){//ノードは、ここでは配列表タブに割り当てられる ノード <K、V> F; INT N-、I、FH; IF(タブ== NULL ||(= N-タブ。長さ)== 0タブは、ノードアレイが空である場合)//次に初期化 タブ = (; //以下の方法initTable源)initTable 他 IF((F = tabAt(タブ、I =(N - 1)・ハッシュ))= = NULL )における(N-1)・ハッシュノードのノードインデックス除去する{// tabAtタブ IF(casTabAt(タブ、I、ヌルの位置は、次に、CASを使用する対応する場合、私がnullの場合、//方法に三番目のパラメータを追加します。これはCASの操作によってロックされていない 新しい新しいノード<K、V>(ハッシュ、キー、値、ヌル)))//ヌルここパラメータ新しく作成されたノードの代表次の要素がnullで BREAK ; // NOロックは、空のビンに追加するとき } 他 IF((FH = f.hash)==ノードは、ハッシュテーブルアレイノードに記載のハッシュ値に等しく移動されたときに)ノード展開では、膨張(拡張マルチスレッドを助ける、helpTransfer方法が膨張を助けることである///)に移動 タブ = helpTransfer(タブは、 F); 他{
//他に、このノードを入力し、このリストをループに、メモが0以上のリストされた場合には、ハッシュFHノード場合、である、次にロック動作、キーを例示し、キーを比較あなたが新たに作成されたノードのノードを追加しない場合に等しいキー値は、その間に置き換えられますがある場合は
、//リストの最後に、それ以外の場合は、ノードのノードTreeBin(赤黒木)タイプと判定されなかった、putTreeValは置換値を呼び出しますまたは赤黒木、putTreeVal方法に加え、以下を参照されたいです。8つ以上のノード数は、ハッシュテーブルは赤黒木にこれを変換する際に V OLDVAL = NULL ; 同期ノード{ロックする(F)//ノード IF(tabAt(タブ、I)= = F){//ノードと他のスレッドは、ノード間の動作を記載されていないかのように同じ、取り出した場合に比較して先行ノードを削除します。 もし(FH> = 0 説明){//ノードのハッシュリストが0より大きい BinCount = 1 ; のため(ノード<K、V> E = F ;; ++ BinCount){//このノードを反復しますハッシュテーブル K EK; IF(e.hash ==ハッシュ&& ((EK = e.key)== ||キー (EK!= NULL && key.equals(EK)は))){//キーとキーとを比較しますハッシュは、同じであれば、交換値と同じである OLDVAL = ; e.val IF!( onlyIfAbsent) e.val =値; BREAK ; } ノード <K、V> PRED = E; IF((E = e.next)== nullが){//ない同じキーノードノード場合、次に作成するために追加しましたハッシュテーブルの端 pred.next = 新しい新しいノード<K、V> (ハッシュ、キー、 値、NULL ); BREAK ; } } } 他 IF(F instanceofの値。TreeBin){//ノードアレイ内のノードノードノードがTreeBinタイプが記述されている場合赤黒木である ノード <K、V> P; BinCount = 2 ; IF((P =((TreeBin < K、V> )F).putTreeVal(ハッシュ、キー、 値))!= NULL ){ OLDVAL = p.val; IF!(onlyIfAbsent) p.val = } } } } IF(BinCount!= 0 ){ IF(BinCount> = BinCount場合TREEIFY_THRESHOLD)//(ノードのハッシュテーブル内の要素の数が等しいTREEIFY_THRESHOLD(8)よりも大きい、赤黒木に変換される) treeifyBin(タブ、I ); IF(OLDVAL!= NULL ) を返すOLDVAL; BREAK ; } } } addCount( 1L 、BinCount); 戻り ヌル; }
民間 最終ノード<K、V> [] initTable(){ ノード <K、V> []タブ; int型のSC; 一方((タブ=表)== NULL || tab.length == 0 ){//分析ノードの配列が空であるかどうか、空でない言葉がハッシュテーブルが初期化されている説明します。 IF((SC = sizeCtl)<0 )//次にハングスレッドThread.yieldこのsizeCtl <0、アレイ別のスレッドの操作(または拡張、または初期化)によって記載され、 Thread.yield()。// ロスト初期人種;ただ、スピン 、他の IF(U.compareAndSwapInt(これ、SIZECTL、SCを、-1 )){
/ ** U.compareAndSwapInt(これ、SIZECTL、SC、-1)安全でないJavaクラスのメソッド、 CASアルゴリズムはアトミック操作を保証するために使用され、CASはすなわち、比較および交換は何ですか、このおおよその説明は、特定を参照してください。https://www.jianshu.com/p/fb6e91b013cc
* CASが変更されていないメモリアドレス値に応じて決定され、この物体が操作される表し、SIZECTL:現在sizeCtlの値は、SCがある古いsizeCtl値は、-1の値に置き換えされようとしています。compareAndSwapIntはsizeCtlかのように、よりSIZECTL最初の値が同じであるだろう
、*は、操作のハッシュテーブル中に説明したのと同じではありません-1にsizeCtlの現在の値を入れて、trueを返します、スレッドが初期化されているハッシュテーブルを他のスレッドを教えてください。あなたはハッシュテーブルを初期化している同じスレッドの取扱説明書をお持ちでない場合は、他のスレッドがハングアップするのを待つだろう。
試し{ IF((タブ=表)== nullの || tab.length == 0){//配列はノードの初期化されていない場合は int型 = N-(SC> 0)? SC:DEFAULT_CAPACITY; //配列のノードのサイズを決定。 @SuppressWarnings( "未チェック") ノード <K、V> [] = NT(ノード<K、V> [])新しい新しいノード<?、?>[N]; //は、アレイの作成 表 =タブ= NTと、テーブルタブに//アレイは、目的のタブは、他のスレッドに伝えることであり、ハッシュテーブルが初期化されています。 SC = N - (N-2 >>> ); } } 最後に{ sizeCtl = SC; // 2つのアップデートsizeCtlのパワーの符号なし右シフトの配列の長さ } BREAKは; } } 戻りタブ; }