4

Collections.synchronizedMap()と、すべてのメソッドが同期されたHashMapのラッパーの違いは何ですか。Collections.synchronizedMap()がすべてのメソッドに対して内部的に同じロックを維持しているため、違いはわかりません。

基本的に、次のコードスニペットの違いは何ですか

Class C {    
    Object o;

    public void foo() {
       synchronized(o) {
           // thread safe code here
       }
    }
}

Class C {
    Object o;

    public synchronized void foo() {

    }
}
4

6 に答える 6

3

違いは1つだけです。

Collections.synchronizedMapは、それ自体とは異なるモニターを使用できます。

同期されたメソッドを使用することは、sychnchonized(this)-blocksを使用することと同じです。つまり、ラッパーがモニターになり、ラッパーの外部からロックされる可能性があります。

外部アプリケーションでモニターをロックしたくない場合は、モニターを非表示にする必要があります。

一方、スレッドセーフな方法で複数のメソッドを呼び出したい場合は、コレクション全体をロックする最も簡単な方法です(ただし、実際にはそれほどスケーラブルではありません)。

追伸:再利用するには、ラッパーを変更せずに後で別のMap実装に切り替えることができるため、クラスをオーバーライドするよりも、メソッド呼び出しをバックアップマップに委任することをお勧めします。

于 2010-02-11T16:12:33.353 に答える
2

どちらのアプローチもオブジェクトのモニターを取得するため、まったく同じように実行する必要があります。違いの主な理由はアーキテクチャです。同期ラッパーを使用すると、基本的な非スレッドセーフのバリエーションを簡単に拡張できます。

どちらも使用しないと言っても、ConcurrentHashMapを使用してください。ロックストライピングを使用するため、どちらのアプローチよりもはるかに高速に使用できます(オーバーヘッドと競合の点で同じであるため)。ロックストライピングにより、バッキングアレイのセグメントを個別にロックできます。これは、2つのスレッドが同じロックの取得を要求する可能性が低いことを意味します。

于 2010-02-11T16:58:16.533 に答える
1

車輪の再発明をせず、APIによって提供されるものを使用してください。

于 2010-02-11T16:32:14.930 に答える
0

すべてとすべての恐れを1つの大きな注目のクラスにまとめるのではなく、常に飾る必要があります。

常にプレーンマップを取得してコレクションで装飾するか、java.util.concurrentを使用して実際のロックを使用すると、マップをアトミックに検査して更新できます。明日は、ハッシュテーブルをツリーマップに変更したいと思うかもしれません。ハッシュテーブルで立ち往生していると、問題が発生します。

于 2010-02-11T06:13:06.960 に答える
0

それで、なぜあなたは尋ねますか?:)クラスがjava.utilパッケージに配置されている場合、魔法が発生し、そのJavaコードがトリッキーな方法で機能すると本当に信じていますか?

実際には、すべてのメソッドを同期された{}ブロックでラップするだけで、それ以上のものはありません。

UPD:違いは、すべての同期作業を自分で行うのではなく、同期コレクションを使用すると、間違いを犯す可能性がはるかに少なくなることです。

UPD 2:ソースでわかるように、モニターとして「mutex」オブジェクトを使用します。メソッドシグネチャ(つまり)で同期修飾子を使用するsynchronized void doSmth()と、オブジェクトの現在のインスタンス(つまりthis)がモニターとして使用されます。以下の2つのコードブロックは同じです。

1.1。

synchronized public void doSmth () {
   someLogic ();
   moreLogic ();
}

synchronized public static void doSmthStatic () {
   someStaticLogic ();
   moreStaticLogic ();
}

2.2。

public void doSmth () {
   synchronized (this) {
      someLogic ();
      moreLogic ();
   }
}

public static void doSmthStatic () {
   synchronized (ClassName.class) {
      someStaticLogic ();
      moreStaticLogic ();
   }
}
于 2010-02-11T15:19:25.783 に答える
0

スレッドセーフが当てはまる場合は、同時実行パッケージのデータ構造を使用してください。ラッパークラスを使用すると、マップへのすべてのアクセスが順次キューに削減されます。

a)マップ内のまったく異なるポイントで操作を実行するのを待機しているスレッドは、同じロックを待機します。スレッドの数に基づいて、これはアプリケーションのパフォーマンスに影響を与える可能性があります。

b)マップ上の複合操作を検討します。シングルロックでラッパーを使用しても役に立ちません。例えば。「存在する場合は見てから追加する」種類の操作。スレッドの同期が再び問題になります。

于 2012-02-15T18:56:14.423 に答える