HashMapの、ハッシュテーブル、のConcurrentHashMap

この本。王は最近、牛は、企業が質問に直面しているインターネットのいくつかをはねのけるよう、インターンシップを探し始めているので、それらのほとんどは、いくつかのJavaは、フロントエンドのHTMLは、JS、jqueryの、だけでなく、問題には触れていなかった長い時間のためのアルゴリズムの数は、正直に言うと、少し不快です、実際には、私はそれは私が実際に空いている場所を感じる、そしてなぜ私の質問を磨くときで、これを書くために地元の知識と、このような多くの抜け穴の多くを知らないのか?複数の操作を行い、そのため、より多くの間違いました。しかし、それは恥ずかしいです企業の多くはまた、質問に直面しているからといって、そう簡単にまっすぐに再び仕上げ書き留めておくことです。

ここで私はまた、牛オフネットワークがないことを示唆しているだけで就職ステーションは、ああ、ああ散歩のフォーラムは、多分あなたは予期しない多くのものを見つけることができる私たちが行使することができる場所、何もブラシです。

インタビューの中で、いくつかの問題がより一般的です。

  1. ハッシュテーブル、HashMapの、ConcurrentHashMapの差?
  2. シーンHashMapのスレッドは、安全でない表示されますか?
  3. HashMapのは、データストレージを置くときの方法を繰り返しかどうかを判断する方法ですか?   
  4. JDK7とJDK8  のHashMapの実装の違いは何ですか?
  5. なぜ、HashMapの長さが2のべき乗でありますか?

直後に何度もいくつかの質問を入れて、再び互いにそれぞれの役割の違いを一般的な理解!実際には、それが再び習得ノックすることができます。

ハッシュ表

  • +キーまたは値が可能かどうか根本的な配列を達成するためのリンクリスト、nullでない、スレッド安全なデータが変更されたときにロック全体のハッシュテーブルを達成するために、スレッドセーフな方法で、低効率、ConcurrentHashMapのは、関連する最適化を行います
  • 初期サイズ11、膨張:NewSizeパラメータ= oldSize新しい* 2 + 1
  • 指標の算出方法:指数=(ハッシュ&0x7FFFFFFFで)%tab.length

HashMapの

  • +基礎リストに実装アレイ、スレッドセーフ、およびNULLキーNULL値を格納することができます
  • 16の初期サイズは、拡張することができる:2の特定のn乗のNewSizeパラメータ= oldSize新しい* 2、サイズ
  • 全体マップ、時間拡張する際の記憶位置を再計算し、再挿入するために、アレイ内の元の要素の膨張
  • 拡張要素が挿入された後(拡張を挿入した場合にそれを再度挿入しない場合、それは無効な拡張を生成します、)裁判官は、有効な拡張がないかもしれない必要があります
  • 要素の総数は、リストの長さを低減するために、拡張操作をトリガー、75%エントリアレイを超えるマップ、より均一な分配エレメント
  • 指標の算出方法:指数=ハッシュ&(tab.length - 1)

*のHashMapの負荷率の初期値も考慮してください。
ハッシュ衝突:モジュロ配列サイズによっていくつかのハッシュ値の後にキーを、配列は、同じ添字上のエントリーチェーンの構図を低下した場合、キートラバースする必要性を見つけるために、チェーン実行エントリの各要素は、()の比較に等しいです。
負荷率:ハッシュ衝突の確率は、キーと値のペアのHashMapの拡張をトリガーする配列のサイズの75%に達したデフォルトを低減するために。従って、100の推定容量場合、即ち、100 / 0.75 = 134を設定する必要が配列のサイズです。
時間のためのスペース:あなたはキー確率が見つけるために時間をスピードアップしたい場合は、さらにハッシュ衝突を減らすために初期サイズを増やし、負荷率を減らすことができます。

HashMapのとハッシュテーブルの区別(〜インタビューの質問が多いテスト)

1. 2つの親クラスの継承の違い

HashMapのクラスは、クラスAbstractMapから継承され、ハッシュテーブルは、Dictionaryクラスから継承されます。(コピー可能)マップ、Cloneableを、直列化(シリアライズ)3つのインターフェイスを実現しながら、しかし、彼らは達成しています。

ここでは、もともとJDKのAPI1.6中国語版の内側に傍受が、それは醜いです、それは静かなミミが描くものを引き継いだ、ああ、誰か他の人のブログであります

 2.外部インタフェースの両方が異なっています

(ハッシュテーブルの要素を提供する)と2つのマルチHashMapのより()メソッドが含まれています。

要素()メソッドは、親クラスDoctionnaryハッシュテーブルから継承されました。要素()メソッドは、列挙値ハッシュテーブルのケースを返します。

含有()メソッドは、ハッシュテーブルは、入来値を含むかどうかを判定する。その役割は、()のcontainsValueと一致しています。実際には、contansValue()はそれが()メソッドが含まれて呼び出し、ハッシュ・テーブルが指定された値を含むかどうかを決定することです。図のソースが含まれています:

パブリック仮想ブール値(オブジェクトキー)が含ま
{ 
    (キー)this.ContainsKeyを返します。
}

3のヌルキーのサポート異なるとヌル値
Hashtableのどちらもサポートしていないにもヌルキーのサポートヌル値。

ハッシュマップ、キー値は、エントリ内に存在します。ヌルキーは、唯一のそのような結合は、ヌル値に対応する1つ以上のキーを持つことができ、要素の順序は不変を保証しない、そのアレイ及びリストを使用して基礎となる、使用されるハッシュコード()メソッドそして、等しい()メソッドは、キーの一意性を保証します。get()メソッドがnull値を返す場合、これはヌルの値に対応するキーについても、可能なハッシュマップのキーではないかもしれません。したがって、ハッシュマップで決定するというべきでのcontainsKey()メソッドキーハッシュマップが存在するかどうかを決定するために()メソッドを得ることができません。
4.別のスレッドセーフセックス

ハッシュテーブルは、それがSynchronizeメソッドに追加された各方法だ、スレッドセーフです。それは独自の方法を達成するために、マルチスレッド環境では、あなたが直接ハッシュテーブルを使用することができ、同期は必要ありません。

HashMap不是线程安全的,在多线程并发的环境下,可能会产生死锁等问题。所以使用HashMap时就必须要自己增加同步处理,

虽然HashMap不是线程安全的,但是它的效率会比Hashtable要好很多。这样设计是合理的。在我们的日常使用当中,大部分时间是单线程操作的。HashMap把这部分操作解放出来了。当需要多线程操作的时候可以使用线程安全的ConcurrentHashMap。ConcurrentHashMap虽然也是线程安全的,但是它的效率比Hashtable要高好多倍。因为ConcurrentHashMap使用了分段锁,并不对整个数据进行锁定。
5.Hash值的计算方法不同

为了求得元素的位置,需要根据元素的Key计算出一个哈希值,然后再用这个哈希值来计算出崔忠的位置。

Hashtable直接使用对象的hashCode。hashCode是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值。然后再使用除留余数发来获得最终的位置。

Hashtable在计算元素的位置时需要进行一次除法运算,而除法运算是比较耗时的。

HashMap为了提高计算效率,将哈希表的大小固定为了2的幂,这样在取模预算时,不需要做除法,只需要做位运算。位运算比除法的效率要高很多。

HashMap的效率虽然提高了,但是hash冲突却也增加了。因为它得出的hash值的低位相同的概率比较高,而计算位运算

为了解决这个问题,HashMap重新根据hashcode计算hash值后,又对hash值做了一些运算来打散数据。使得取得的位置更加分散,从而减少了hash冲突。当然了,为了高效,HashMap只做了一些简单的位处理。从而不至于把使用2 的幂次方带来的效率提升给抵消掉。

ConcurrentHashMap

  • 底层采用分段的数组+链表实现,线程安全。
  • key和value都不能为null。
  • 通过把整个Map分为N个Segment,可以提供相同的线程安全,但是效率提升N倍,默认提升16倍。
  • Hashtable的synchronized是针对整张Hash表的,即每次锁住整张表让线程独占,ConcurrentHashMap允许多个修改操作并发进行,其关键在于使用了锁分离技术
  • 有些方法需要跨段,比如size()和containsValue(),它们可能需要锁定整个表而而不仅仅是某个段,这需要按顺序锁定所有段,操作完毕后,又按顺序释放所有段的锁
  • 扩容:段内扩容(段内元素超过该段对应Entry数组长度的75%触发扩容,不会对整个Map进行扩容),插入前检测需不需要扩容,有效避免无效扩容

这个就很棒了,上面总结的源于某猿大神,Java5提供的ConcurrentHashMap就像是HashTable的升级版,扩容性更强。

在HashMap中,通过get()返回的null值,既可以表示返回该Key所对应过的Value是null值,也可以表示为没有该Key,在这种情况下就应该采用ConcurrentHashMap。

来看一张简单的类图:

ConcurrentHashMap是由Segment数组结构和HashEntry数组结构组成。Segment是一个可重入锁(ReentrantLock),在ConcurrentHashMap里扮演锁的角色;HashEntry则用于存储键值对数据。一个ConcurrentHashMap里包含一个Segment数组。Segment的结构和HashMap类似,是一种数组和链表结构。一个Segment里包含一个HashEntry数组,每个HashEntry是一个链表结构的元素,每个Segment守护着一个HashEntry数组里的元素。当对HashEntry数组的数据进行修改时,必须首先获得与它对应的segment锁。

 Hashtable中采用的锁机制是一次锁住整个hash表,从而在同一时刻只能由一个线程对其进行操作;而ConcurrentHashMap中则是一次锁住一个桶。

简单理解就是,ConcurrentHashMap是一个Segment数组,Segment通过继承ReentrantLock来进行加锁,所以每次需要加锁的操作锁住的是一个Segment,只要保证每个Segment是线程安全的,也就实现了全局的线程安全。重申一下,Segment数组不能扩容,扩容是Segment数组某个位置内部的数组HashEntry<K,V>[]进行扩容,扩容后,容量为原来的2倍。可以回顾下出发扩容的地方,put的时候,如果判断该值的插入会导致该Segment的元素个数超过阈值,那么先进行扩容,再插值。

おすすめ

転載: www.cnblogs.com/wudidamowang666/p/11286279.html