JavaコンテナのHashtable、HashMap、ConcurrentHashMapの原則

HashMap

  • 非スレッドセーフコンテナー

  • ハッシュテーブル配列のインデックスを取得するために、ハッシュアルゴリズムと配列の長さを通じてハッシュテーブル(配列)キーを内部的に維持します。

ハッシュアルゴリズム

static final int hash(Object key) {
   int h;
   return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

ここでは、キーのハッシュ値とハッシュ値を右に16ビットシフトし、OR演算(低次のランダム性が豊富)を実行します。目的は、ハッシュが2より大きいときにハッシュ値ステータスの衝突確率を16乗することです(ハッシュ値が高すぎるとハッシュレートが高すぎるため)。この方法をテストすると、衝突確率を10%減らすことができます。
hsah値を取得したら、次のようにハッシュテーブルのインデックスを取得します
(n-1)&hash //ハッシュテーブルの下位を破棄して、配列の長さより短いインデックスを取得します(n:配列の長さ、配列の最大インデックスは常に2n-1で、バイナリは有効です)ビットは常に1の低ビットマスクです

hashMapの詳細なハッシュ演算

ハッシュテーブル

ハッシュテーブルのマスク操作が衝突した場合はどうすればよいですか?デフォルトのハッシュテーブルが二重にリンクされたリストに保存されている問題ではありません
、衝突が発生した場合、リストの末尾にデータを挿入していきます


ただし、リンクリストが長すぎるときにデータを取得すると問題が発生する可能性があります。
したがって、リンクリストの長さが8より大きい場合、hashMapはバランスの取れたツリー構造を拡張します。赤黒木
ツリー構造の検索効率がはるかに高いです
が、なぜ?へのforEachリンクリスト構造を保持します。

ハッシュテーブルの拡張

ハッシュテーブルのデフォルトの初期長は16で、初期長はコンストラクターで指定できます(リンクリストの実際の長さは、入力長に従って自動的に計算され、適切な長さが選択されます)。

/**
  * 这里的代码有时间在做深度研究
  * Returns a power of two size for the given target capacity.
  */
 static final int tableSizeFor(int cap) {
     int n = cap - 1;
     n |= n >>> 1;
     n |= n >>> 2;
     n |= n >>> 4;
     n |= n >>> 8;
     n |= n >>> 16;
     return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
 }

ハッシュテーブル内のデータの数(指定可能)16 * 0.75 * 2各時間より膨張大きくなる場合に
ハッシュテーブルがMIN_TREEIFY_CAPACITY = 64よりも大きい場合、この値は、テーブルには、タブの木であることができる
か、浴槽ツリーではなく要素が多すぎると展開します


ハッシュ表

  • スレッドセーフ(同期ロックによって実装)
  • 内部構造はhashMapハッシュテーブル+リンクリストに似ていますが、jdk8では赤黒ツリーのアップグレードは行われていません。hashTableなどのシリアルスレッドセーフコンテナーが破棄された可能性があります。ConcurrentHashMapには絶対的な利点があります。

ConcurrentHashMap

  • スレッドセーフ
  • 内部ストレージ構造は、hashMapとほぼ同じです(jdk8は以前はセグメント化されたロックでした)
  • 安全な同時実行を実現するために、cas(比較および置換)+ volatile +同期キーワードを使用します
  • 同期の使用は、テーブルの単一のリンクリストを操作する場合にのみ使用されることはめったにありません(他の変更を除いて(削除|| put)はgetに影響しません)
  • 悲観的ロックと楽観的ロック:
    悲観的ロックとは、スレッドがロックを占有し、ロックを解放するまでロックを必要とする他のすべてのスレッドを待機させる場合、つまり、典型的なロックは排他的であることを意味します同期されます。楽観的ロックとは、操作はロックされず、試行する姿勢で操作を実行することを意味します。操作が失敗するか、操作が競合する場合は、目標が達成されるまで再試行を入力してください。
ハッシュ値の計算は少し異なります。
 static final int spread(int h) {
   return (h ^ (h >>> 16)) & HASH_BITS; // 生成一个 小于long int 最大值的hash
 }
ConcurrentHashMapの浅い読み取りについては、ここのみ

並行性に関しては、ConcurrentHashMapは複雑です。別の投稿更新を投稿する

元の記事を17件公開 24 件を獲得 28万回以上表示

おすすめ

転載: blog.csdn.net/qq_22956867/article/details/79414338