EDITORIAL
すべてのソースコードのConcurrentHashMapについてのこの記事は、に基づいているJDK 1.6、原則ので、全体的に把握し、理解がJDKの異なるバージョン間でほとんど差だったが、私たちのConcurrentHashMapのデータ構造には影響を与えません。
ConcurrentHashMapのは、効率的な同時バージョンをサポートするために、スレッドセーフのHashMapであるJUC(java.util.concurrentパッケージ)、の重要なメンバーです
ConcurrentHashMapの概要
HashMapのは、Javaのコレクションフレームワークの重要なメンバーで最も一般的に使用された米国の地図ファミリー(下図参照します)。しかし残念ながら、HashMapのはスレッドセーフではありません
同時シナリオのHashMap(Collections.synchronizedMap(地図<K、V> M))で同期することによりハッシュテーブルラッパーおよびパッケージはHashMapを置き換えることができますが、この欠点をHashMapのは、通常は、不都合が生じるが、彼らはの使用によるものです異なるスレッド間の同時アクセスを同期するので、パフォーマンスの問題をもたらすグローバルロックを無視することはできません。幸いなことに、私たちはこの問題を解決するためのJDKは、それはHashMapのの効率的なスレッドセーフなバージョンを提供 - のConcurrentHashMap
ConcurrentHashMapのでは、それが読み取られるまたは書込み動作するかどうかは、高い性能を保証することができる:読み出し動作が行われると(ほぼ)ロック、ロックセグメントの技術を介して書き込み動作のみロックセグメントを操作しないとき必要他のセグメントへのクライアントアクセスに影響を与えず。具体的には、理想的な条件下で、ConcurrentHashMapの16件の同時実行書き込み動作のスレッド(同時実行レベルが16に設定されている場合)をサポートし、それらのスレッドの任意の数を読み取ることができ
ConcurrentHashMapの効率的な同時性があることを確認するために、次の三つの領域を介して行われ
- 同時環境を確保するために、ロックセグメント化技術に書き込むことにより
- HashEntry不変、メモリ、可視性によって、読み出しの効率的かつ安全な運転を確保するための機構揮発性変数をロック再読
- 二つのオプションのセキュリティをロックし、ロックしないことにより、制御動作のスパン
JDKで定義されているのConcurrentHashMap
ConcurrentHashMapのクラスは、2つの静的内部クラスが含まれています
- HashEntry:はい特定K / Vをカプセル化するために使用される、典型的な4タプル
- セグメント:ロックとして機能するように、各バレルは、オブジェクトの数によって連結されているバレルの各セグメントオブジェクトガードConcurrentHashMapの整数(セグメントが小さいハッシュテーブルとして見ることができる)、アップHashEntryリスト
ConcurrentHashMapのキーは、ハッシュテーブルのバケットを通して全体の1/16について各セグメントガードをハッシュすることができたとしても、既定の同時実行レベル下における16セグメントオブジェクトの配列を作成します。
クラス構造の定義
ConcurrentHashMapのは、以下のようにJDKに定義されているクラスAbstractMapのConcurrentMapインタフェースおよび実装を継承しました。
public class ConcurrentHashMap<K, V> extends AbstractMap<K, V>
implements ConcurrentMap<K, V>, Serializable {
...
}
メンバ変数が定義されている
位置決め部のための2つの属性を追加します** HashMapの、のConcurrentHashMapと比較して、そしてsegmentMask segmentShiftです。**また、それはHashMapのとは異なり、ConcurrentHashMapの基礎構造セグメントのアレイよりもむしろArrayオブジェクトであります
final int segmentMask; // 用于定位段,大小等于segments数组的大小减 1,是不可变的
final int segmentShift; // 用于定位段,大小等于32(hash值的位数)减去对segments的大小取以2为底的对数值,是不可变的
final Segment<K,V>[] segments; // ConcurrentHashMap的底层结构是一个Segment数组
定義セグメント:セグメントの
セグメント・オブジェクトがロックとして働くことができるように、セグメントReentrantLockのクラスは、クラスから継承
セグメントクラスでは、変数は、管理を含む各アレイHashEntryオブジェクトテーブルセグメントオブジェクトの数を示すカウンタでカウント、すなわち、HashEntryセグメントオブジェクトの総数が含まれます。特に注目すべき理由はなく、グローバルカウンタのConcurrentHashMap、ConcurrentHashMapの同時実行の考慮を使用するのでは、各セグメントオブジェクト内のカウンタが含まれていることですので、あなたが全体のConcurrentHashMapをロックせずにカウンタを更新する必要がある場合
基本要素:HashEntry
とHashMapのエントリは同様に、HashEntryは、4つの類似のドメインを含むが、鍵、ハッシュ値と次あります。違いは、値フィールドはConcurrentHashMapの操作がロックを必要としない読み取られる、揮発性によって変更されるので、ほとんどHashEntryオブジェクトは不変であるが、HashEntryにクラス、鍵、ハッシュ、次のフィールドがfinalとして宣言されている、ということです重要な理由
スレッドがロックを必要としない操作を読んでConcurrentHashMapのもう一つの重要な理由は、最新の値を、読むことを確実にするために読み取ることができるように、値フィールドので、揮発性の修正されています。
ConcurrentHashMapのコンストラクタ
1、ConcurrentHashMapの(INT InitialCapacityの値、フロートloadFactor、INTのconcurrencyLevel)
この構成は、指定された容量、負荷係数、および指定されたセグメント/同時実行レベルの指定数(それが2のべき乗でない場合、それは2のパワーに調整される)空のConcurrentHashMapを有する構成を機能するように意図されています
2、ConcurrentHashMapの(INT InitialCapacityの値、フロートloadFactor)
この構成は、指定された容量、およびデフォルトの負荷率指定同時実行レベル(16)空のConcurrentHashMapを有する構成を機能するように意図されています
3、ConcurrentHashMapの(INT InitialCapacityの値)
この構成は、指定された容量設定は、デフォルトの負荷係数(0.75)と同時実行のデフォルトレベル(16)空のConcurrentHashMapで機能することが意図されています
4、ConcurrentHashMapの()
この構成は、デフォルトの初期容量(16)、デフォルトの負荷係数(0.75)と同時実行の既定レベルを有する構成を機能するように意図されている(16)空のConcurrentHashMap
5、ConcurrentHashMapの(地図<?延びK、?延びV> M)
このコンストラクタは、ConcurrentHashMapのを構築することが意図されている指定されたMapと同じ要素、16未満では(特にサイズ指定マップに依存する)、負荷率が0.75であり、同時実行レベルは16であり、Javaのコレクションフレームワーク仕様を提供お勧めしないの初期容量
概要
ここでは、我々は3つの非常に重要なパラメータは言う:初期容量、負荷係数、および並行処理レベルを、これらの3つのパラメータはConcurrentHashMapのパフォーマンスに影響を与える重要なパラメータであります
ConcurrentHashMapのデータ構造
ConcurrentHashMapの異なる部分に分かれたセグメント(セグメント)を使用して、ConcurrentHashMapのセグメンテーション技術をロックされ、それによって同時に実行される複数の改変を可能にハッシュテーブルの異なる部分を制御するために、ロックの異なる修飾を使用することができるのConcurrentHashMap芯物質
ConcurrentHashMapの同時アクセス
ConcurrentHashMapのでは、一般船舶の操作に構造的な変更を加えるために、ロックが完了することができる必要はありませんが、読み取り操作を行うマッピングテーブルのスレッドが(例えば、操作をPUTなど、操作を削除する)それをロックする必要があります。
ねじ山付きセグメント化されたロック機構のうち同時実行書き込み:置く(キー、vlaue)
ConcurrentHashMapのでは、プットを含む典型的な構造的な修正操作は、削除して、明確な、ConcurrentHashMapの操作を行い、構造改質処理の一例としての第1の動作を置くために、すべてのを聞かせて
public V put(K key, V value) {
if (value == null)
throw new NullPointerException();
int hash = hash(key.hashCode());
return segmentFor(hash).put(key, hash, value, false);
}
ConcurrentHashMapのHashMapのとは異なり、両方の許可キーがnull、null値が許可されていない値
ソース以下のセグメント()メソッドを配置segmentFor
final Segment<K,V> segmentFor(int hash) {
return segments[(hash >>> segmentShift) & segmentMask];
}
重要な要素の高いnビットのハッシュ値の場所を正確にセグメントを決定することができます
コードセグメントは、次のような方法である()を挿入します
V put( K key, int hash, V value, boolean onlyIfAbsent )
{
lock(); /* 上锁 */
try {
int c = count;
if ( c++ > threshold ) /* ensure capacity */
rehash();
HashEntry<K, V>[] tab = table; /* table是Volatile的 */
int index = hash & (tab.length - 1); /* 定位到段中特定的桶 */
HashEntry<K, V> first = tab[index]; /* first指向桶中链表的表头 */
HashEntry<K, V> e = first;
/* 检查该桶中是否存在相同key的结点 */
while ( e != null && (e.hash != hash || !key.equals( e.key ) ) )
e = e.next;
V oldValue;
if ( e != null ) /* 该桶中存在相同key的结点 */
{
oldValue = e.value;
if ( !onlyIfAbsent )
e.value = value; /* 更新value值 */
}else { /* 该桶中不存在相同key的结点 */
oldValue = null;
++modCount; /* 结构性修改,modCount加1 */
tab[index] = new HashEntry<K, V>( key, hash, first, value ); /* 创建HashEntry并将其链到表头 */
count = c; /* write-volatile,count值的更新一定要放在最后一步(volatile变量) */
}
return(oldValue); /* 返回旧值(该桶中不存在相同key的结点,则返回null) */
} finally {
unlock(); /* 在finally子句中解锁 */
}
}
ハッシュテーブルと比較すると、1つのスレッドだけが操作を読み書き同期ラッパーのHashMapでパッケージ、ConcurrentHashMapのは、同時アクセスの性能の質的向上となっています。理想的な状況では、ConcurrentHashMapの16件の同時実行書き込み動作のスレッド(同時実行レベルが16に設定されている場合)、および読み取りスレッドの任意の数をサポートすることができます