1

我正在尝试解决间歇性故障,该故障似乎与从 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() 或 remove 可能导致这种行为?

我应该提一下,据我所知,容器只被一个线程访问。我已经在他的文档中读到 HashMap 类不是“同步的”。

4

9 回答 9

7

remove/get 和 put 之间存在细微差别(尽管我猜你有线程问题)。

remove/的参数get类型为Object; 因为put它是类型K。其原因之前已经说过很多次了。这意味着它在拳击方面存在问题。我什至不会猜测规则是什么。如果一个值Byte在一个地方被装箱,而Short在另一个地方被装箱,那么这两个对象不可能相等。

List.remove(int)和也有类似的问题List.remove(Object)

于 2009-01-14T21:19:37.180 回答
6

我假设每次您检查该项目的存在时,您肯定会使用 a shortor Short argumentto Map.get()or Map.contains()?

这些方法采用 Object 参数,因此如果您将它们传递给它们int,它将被转换为 anInteger并且永远不会匹配 Map 中的任何项目,因为它们都将具有Short键。

于 2009-01-14T21:25:43.797 回答
4

HashMap 类中没有“异步”效果。只要你把东西放在那里,它就在那里。您应该进行双重和三重检查以确保没有线程问题。

我唯一能想到的另一件事是您正在某处制作 HashMap 的副本。副本显然不会受到您在原件中添加内容的影响,反之亦然。

于 2009-01-14T21:10:38.087 回答
2

只有一个建议...您专注于对 HashMap 的访问,但我想知道您是否还应该查看您的 generate_transaction_id() 是否是线程安全的,或者它是否以意想不到的方式运行。

于 2009-01-14T22:44:56.117 回答
2

您是否已覆盖equals()但不在hashCode()模型对象中?怎么样compareTo()?如果你弄错了,集合的行为确实会很奇怪。

检查equals()compareTo()上的 Java 实践。

于 2009-01-14T23:01:23.043 回答
1

所以你知道HashMap's 不是线程安全的。你确定它只被一个线程访问吗?毕竟,间歇性故障与频繁的线程有关。如果没有,你可以用 包裹它Collections.synchronizedMap(),像这样:

Collections.synchronizedMap(transactions);

你总是可以尝试,这样你就可以消除这种可能性。

应该指出的是,这只是用一个所有方法同步的原始地图包装。如果访问是本地化的,您可能需要考虑使用同步块。

于 2009-01-14T21:01:14.347 回答
1

这个 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

当然,如果“据您所知”部分不正确,这只能是一个解决方案。

于 2009-01-14T23:12:32.987 回答
0

已经在一些回复中提到了线程,但是您是否考虑过多个线程使用的对象的可见性问题?如果您将对象放入一个线程中的集合中,则可能(并且很常见)除非您在集合上正确同步,否则它不会“发布”到其他线程。

线程和锁

Java中的同步和线程安全

于 2009-01-14T23:25:14.367 回答
0

正如其他人所观察到的,您必须知道 HashMap 是否仅由一个线程访问。CollectionSpy是一个新的分析器,它可以让你立即找出所有容器有多少线程执行任何访问。有关详细信息,请参阅www.collectionspy.com 。

于 2009-07-03T19:29:44.930 回答