1

ハッシュマップの構造を変更するもの(配置または削除)を同期する必要があることは知っていますが、ハッシュマップの読み取りも同期する必要があるようです。そうしないと、別のスレッドが構造を変更している間に読んでいる可能性がありますハッシュマップ。

そのため、gets と put をハッシュマップに同期します。私がテストできる唯一のマシンは、すべて 1 つのプロセッサしか搭載していないため、システムが稼働して障害が発生し始めるまで、実際の同時実行性はありませんでした。ハッシュマップにアイテムがありませんでした。これは、2 つのスレッドが同時に書き込みを行っていたためだと思いますが、以下のコードに基づくと、これは不可能なはずです。スレッドの数を 1 に下げると、問題なく動作し始めたので、間違いなくスレッドの問題です。

詳細:

// something for all the threads to sync on
private static Object EMREPORTONE = new Object();


    synchronized (EMREPORTONE)
      {
        reportdatacache.put("name.." + eri.recip_map_id, eri.name);
        reportdatacache.put("subjec" + eri.recip_map_id, eri.subject);
        etc...
      }

...そして他の場所....

    synchronized (EMREPORTONE)
      {
        eri.name = (String)reportdatacache.get("name.." + eri.recip_map_id);
        eri.subject = (String)reportdatacache.get("subjec" + eri.recip_map_id);
        etc...
      }

以上です。関数間で reportdatacache を渡しますが、それはハッシュマップへの参照にすぎません。

もう 1 つの重要な点は、これが appserver でサーブレットとして実行されていることです (具体的には iplanet ですが、誰も聞いたことがないことは知っています)。

しかし、とにかく、EMREPORTONE は Web サーバー プロセスに対してグローバルであり、2 つのスレッドが互いに踏み込むことはできませんが、私のハッシュマップは壊れています。何かご意見は?

4

3 に答える 3

1

サーブレット コンテナー環境では、静的変数はクラスローダーに依存します。したがって、同じ静的インスタンスを扱っていると思うかもしれませんが、実際にはまったく異なるインスタンスである可能性があります。

さらに、他の場所でエスケープされた参照によってマップを使用していないかどうかを確認し、そこからキーを書き込み/削除します。

はい、代わりに ConcurrentHashMap を使用してください。

于 2012-07-05T18:32:40.940 に答える
1

私が見ているように、ここには3つの可能性があります:

  1. 2 つの異なるオブジェクトをロックしています。 ただし、にアクセスするコードEMREPORTONEは1 つのファイルにのみ含まれます。わかりました、それではありません。ただし、代わりにロックオンすることをお勧めします。よりクリーンなコード。private staticreportdatacachereportdatacacheEMREPORTONE

  2. reportdatacacheどこかへの読み取りまたは書き込みが欠落しています。ではないマップへの他のアクセスがありますsynchronized。キャッシュから削除されることはありませんか?

  3. これは同期の問題ではなく、競合状態の問題です。ハッシュマップのデータは問題ありませんが、キャッシュにあることを期待していますが、他のスレッドによってまだ保存されていません。2 つのリクエストが同時にeri同じものを受け取り、両方ともキャッシュに値を入れているのではないでしょうか? によって返される古い値put(...)が常に null であるかどうかを確認してください。アイテムがマップにないことをどのように知っているかについてもっと説明すると、これに役立つかもしれません.

余談ですが、あなたはこれをやっています:

reportdatacache.put("name.." + eri.recip_map_id, eri.name);
reportdatacache.put("subjec" + eri.recip_map_id, eri.subject);

eriしかし、実際にはIDで保存する必要があるようです。

reportdatacache.put(recip_map_id, eri);

"name.."次に、プレフィックスを使用して偽のキーを作成していません。NameSubject private static classまたは、名前とサブジェクトをキャッシュに保存するを作成する必要があるかもしれません。クリーナー。

ここで何かが役立つことを願っています。

于 2012-07-05T20:26:57.623 に答える
1

はい、同期は書き込み時だけでなく、読み取り時にも重要です。書き込みは相互排除の下で実行されますが、リーダーはマップの誤った状態にアクセスする可能性があります。

いかなる状況においても、Java Collectionsを手動で同期することはお勧めできません。スレッドセーフな対応するCollections.synchronizedMapConcurrentHashMapがあります。それらを使用すると、それらへのアクセスがマルチスレッド環境で安全であることを保証します。

さらにヒントを言うと、誰もが にアクセスしているようですdatareportcache。そのオブジェクトのインスタンスは 1 つだけですか? キャッシュ自体で同期しないのはなぜですか? ただし、問題を解決しようとするときは忘れて、java.util.concurrentの砂糖を使用してください。

于 2012-07-05T18:28:47.770 に答える