web-dev-qa-db-ja.com

HashtableとCollections.synchronizedMap(HashMap)の違い

私の知る限り、 _Java.util.Hashtable__Java.util.Map_ インターフェイスの各メソッドを同期しますが、 Collections.synchronizedMap(hash_map) は、実際の_hash_map_への呼び出しを委任する同期メソッドを含むラッパーオブジェクトを返します(間違っている場合は修正してください)。

2つの質問があります:

  1. すべてのメソッドを同期し、ラッパークラスを作成すると、どのような違いが生じますか?どちらを選択するシナリオは何ですか?

  2. Collections.synchronizedMap(hash_table)を実行するとどうなりますか?これは、通常の_Java.util.Hashtable_を単に使用するのと同じでしょうか?

45

少しの(うまくいけば正しい)研究から得た答えは次のとおりです。

  1. どちらも同程度の同期を提供します。 Collections.synchronizedを介してHashtableをラップする場合、同期の度合いは同じですが、別の冗長レイヤーがあります。

  2. HashtableCollections.synchronizedMap(HashMap)の主な違いは、APIレベルでより多く存在します。 HashtableはJavaのレガシーコードの一部であるため、Hashtable AP​​Iが拡張されてMapインターフェイスを実装し、Javaのコレクションフレームワークの一部になることがわかります。つまり、HashtableCollections.synchronizedMap()でラップすると、ラップされたHashtableのAPIはMap AP​​Iに制限されることになります。したがって、HashtableのAPIがbehaviorの定義に含まれている場合、明らかに変更または制限されます。

15
Nadir Muzaffar

両方のクラスの実装で見つけることができるもう1つの違いは、次のとおりです。

Hashtableクラスにはすべてのメソッドが同期されています。つまり、ロックはメソッドレベルで実行されるため、mutexはalwaysHashtableオブジェクト(-this)レベルであると言えます。 。

Collections.synchronizedMap(Map)メソッドは、SynchronizedMapクラスの内部クラスであるCollectionsのインスタンスを返します。このクラスのすべてのメソッドは、mutexを使用したSynchronizedブロックにあります。ここでの違いはミューテックスにあります。内部クラスSynchronizedMapには2つのコンストラクターがあり、1つは引数としてMapのみを受け取り、もう1つは引数としてMapObject(mutex)を受け取ります。デフォルトでは、Mapのみを渡す最初のコンストラクターを使用する場合、thisがミューテックスとして使用されます。ただし、開発者は、MapメソッドのロックがそのObjectに対してのみ行われるため、Hashtableよりも制限が少ない別のmutexオブジェクトを第2引数として渡すことができます。

•したがって、Hashtableはメソッドレベルの同期を使用しますが、Collections.synchronizedMap(Map)は、Synchronizedブロックで提供されたミューテックスを開発者がロックする柔軟性を提供します。

60
mankadnandan

Javaクラスライブラリに表示される最初の連想コレクションクラスは、JDK 1.0の一部であるHashtableでした。Hashtableは、使いやすく、スレッドセーフで、連想マップ機能を提供しました。ただし、Hashtableのすべてのメソッドは同期されていましたが、競合しない同期には、測定可能なパフォーマンスコストがありました。Hashtableの後継であるHashMapは、Collectionsフレームワークの一部として登場しましたJDK 1.2では、非同期の基本クラスと同期ラッパー、Collections.synchronizedMapを提供することでスレッドセーフに対応しました。スレッドセーフから基本機能を分離するCollections.synchronizedMapにより、同期が必要なユーザーはそれを使用できますそれを支払う必要はありませんでした必要があります。

HashtableとsynchronizedMapの両方で行われる同期への単純なアプローチ(Hashtableまたはsynchronized Mapラッパーオブジェクトの各メソッドの同期)には、2つの主な欠点があります。一度に1つのスレッドしかハッシュテーブルにアクセスできないため、これはスケーラビリティの障害です。同時に、多くの一般的な複合操作では追加の同期が必要になるため、真のスレッドセーフティを提供するには不十分です。 get()やput()などの単純な操作は、追加の同期なしで安全に完了することができますが、反復やput-if-absentなどの一般的な操作シーケンスがいくつかあり、データ競合を避けるために外部同期が必要です。

次のリンクはソースであり、詳細情報があります。 Concurrent Collections Classes

4
bchetty

違いは明らかなAPIレベルですべてではなく、実装レベルでは多くの微妙な点があります。たとえば、Hashtableは、HashMapの提供されたキーのハッシュコードの高度な再計算を行わず、ハッシュの衝突を減らします。一方、Hashtable#hashCode()は、自己参照ハッシュテーブルの無限再帰を回避して、「自己参照ハッシュテーブルを備えた特定の1.1時代のアプレットが機能する」ようにします。

ただし、一般的には、Hashtableが基本的な正確性と後方互換性を超えたさらなる改善または改良を受け取ることを期待するべきではありません。深いJava過去の遺物と見なされます。

3
Marko Topolnik

注意すべきもう1つの違いは、-HashTableはnullキーまたはnull値を許可しないのに対して、-HashMapは1つのnullキーと任意の数のnull値を許可することです。 synchronizedMapはHashMapのラッパーであるため、nullキーと値に関する動作はHashMapと同じです。

2
Rahul Jangra

明白な(または明白に間違っている)と述べるリスクは、以下の違いではありません。

同期ラッパーは、自動同期(スレッドセーフ)を任意のコレクションに追加します

http://docs.Oracle.com/javase/tutorial/collections/implementations/wrapper.html そして言い続ける

この方法で作成されたコレクションは、ベクターなどの通常同期されたコレクションと同じくらいスレッドセーフです。

HashMapと並行性に関する問題については、このスレッドをご覧ください- Hashmap並行性の問題 良い例は次のとおりです。

あなたが説明する条件は、HashMapによって満たされません。マップの更新プロセスはアトミックではないため、マップが無効な状態になる可能性があります。複数の書き込みを行うと、破損状態のままになる可能性があります。 ConcurrentHashMap(1.5以降)はあなたが望むことをします。

https://stackoverflow.com/a/1003071/201648

「これをいつ使うべきか」という点では、同時実行性が必要な場合は同期化されたコレクションを使用する傾向があると思います。

動作の変更に関して

明示的な反復子を使用する場合は、同期ブロック内から反復子メソッドを呼び出す必要があります。このアドバイスに従わないと、非決定的な動作が発生する場合があります

提供されている(Oracle)リンクで指定された同期を使用すると、さらに多くの結果が生じます。

1
Aaron Newton