質問

HashMapからオブジェクトを削除し、新しいキーを使用して同じオブジェクトを戻すことに関連していると思われる断続的な障害のトラブルシューティングを試みています。私のHashMapは次のように作成されます。

transactions = new HashMap<Short, TransactionBase>();

再割り当てを行うコードは次のとおりです。

transactions.remove(transaction.tran_no);
transaction.tran_no = generate_transaction_id();
transactions.put(transaction.tran_no, transaction);

私が見ている断続的な動作は、この直後に実行されるコードは、配置可能なトランザクションオブジェクトに依存しているため、新しいトランザクションIDを使用してトランザクションオブジェクトを見つけられないようです。ただし、将来のある時点で、トランザクションを見つけることができます。ストローを引っ張って、このような動作を引き起こす可能性のあるput()または削除する非同期効果はありますか?

私が知る限り、コンテナは1つのスレッドのみによってアクセスされていることに言及する必要があります。彼のドキュメントでは、クラスHashMapが「同期」されていないことをすでに読んでいます。

役に立ちましたか?

解決

「非同期」はありませんHashMapクラスの効果。そこに何かを入れるとすぐに、それはそこにあります。スレッドの問題がないことを確認するために、ダブルおよびトリプルチェックする必要があります。

他に考えられることは、HashMapのコピーをどこかに作成していることだけです。コピーは明らかに、オリジナルにアイテムを追加しても影響を受けません。逆も同様です。

他のヒント

remove / getとputにはわずかな違いがあります(私の推測では、スレッドの問題があると思われます)。

remove / get のパラメーターは、 Object 型です。 put の場合、タイプは K です。その理由は何度も述べられています。これは、ボクシングに問題があることを意味します。私はルールが何であるかを推測するつもりさえありません。値が1つの場所で Byte として、別の場所で Short としてボックス化された場合、これら2つのオブジェクトは等しくなりません。

List.remove(int)および List.remove(Object)にも同様の問題があります。

アイテムの存在を確認するたびに、 Map.get()<に short または Short引数を必ず使用していると思います/ code>または Map.contains()

これらのメソッドはオブジェクトの引数を取るため、 int を渡すと Integer に変換され、マップ内のどのアイテムにも一致しなくなります。 ショートキー。

1つの提案... HashMapへのアクセスに焦点を当てていますが、generate_transaction_id()がスレッドセーフかどうか、または予期しない動作をしているのかどうかも確認する必要があるのでしょうか。

モデルオブジェクトで equals()をオーバーライドしましたが、 hashCode()はオーバーライドしませんでしたか? compareTo()はどうですか?これらが間違っていると、コレクションは実際に奇妙な動作をします。

equals()および compareTo()

このgenerate_transaction_id()関数は何をしますか? 16ビットのGUIDのようなものを生成している場合、ハッシュの衝突が簡単に発生する可能性があります。スレッドと組み合わせると、次のものが得られます。

T1: transaction1.tran_no = generate_transaction_id();    => 1729
T2: transaction2.tran_no = generate_transaction_id();    => 1729
T1: transactions.put(transaction1.tran_no, transaction1); => map.put(1729, transaction1)
T2: transactions.put(transaction2.tran_no, transaction2); => map.put(1729, transaction2)
T1: int tran_no = transactions.get(1729);               => transaction2
T1: transactions.remove(transaction.tran_no);           => map.remove(1729)
T2: int tran_no = transactions.get(1729);               => null

もちろん、これは、「あなたの知る限り」の部分が真実でない場合にのみ解決策となります。

つまり、 HashMap はスレッドセーフではないことを知っています。 1つのスレッドのみがアクセスしていると確信していますか?結局のところ、断続的な障害は頻繁にスレッド化に関連しています。そうでない場合は、 Collections.synchronizedMap() のように:

Collections.synchronizedMap(transactions);

その可能性を排除できるように、いつでも試すことができます。

これは、元のマップをすべてのメソッドが同期されたマップでラップするだけであることに注意してください。アクセスがローカライズされている場合は、同期ブロックの使用を検討できます。

スレッド化については既にいくつかの回答で言及されていますが、複数のスレッドで使用されるオブジェクトの可視性の問題を考慮しましたか?オブジェクトを1つのスレッドのコレクションに入れると、「公開」されない可能性があります(非常に一般的です)。コレクションで適切に同期していない限り、他のスレッドに。

スレッドとロック

Javaでの同期とスレッドセーフ

HashMapが1つのスレッドによってのみアクセスされるかどうかを知る必要があることを他の人が観察しているように。 CollectionSpy は、すべてのコンテナについて、アクセスを実行するスレッドの数を即座に確認できる新しいプロファイラです。詳細については、 www.collectionspy.com をご覧ください。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top