奇怪的HashMap.put()行为

时间:2009-01-14 20:58:06

标签: java hashmap

我正在尝试解决间歇性故障,这种故障似乎与从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()或删除会产生这种行为的异步效果吗?

我应该提一下,据我所知,容器只能由一个线程访问。我已经在文档中读到类HashMap没有“同步”。

9 个答案:

答案 0 :(得分:7)

删除/获取和放置之间略有不同(虽然我的猜测是你有线程问题)。

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

List.remove(int)List.remove(Object)存在类似问题。

答案 1 :(得分:6)

我认为,每当您检查项目是否存在时,您肯定会使用shortShort argumentMap.get()Map.contains()

这些方法采用对象参数,因此如果您将int传递给它,它将转换为Integer并且永远不会匹配地图中的任何项目,因为它们都会有Short个键

答案 2 :(得分:4)

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

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

答案 3 :(得分:2)

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

答案 4 :(得分:2)

您是否在模型对象中覆盖了equals()但未覆盖hashCode()compareTo()怎么样?如果你弄错了,收藏品确实会表现得很奇怪。

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

答案 5 :(得分:1)

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

Collections.synchronizedMap(transactions);

您可以随时尝试,以便消除这种可能性。

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

答案 6 :(得分: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

当然,如果“尽你所知”的部分不是真的,这只能是一个解决方案。

答案 7 :(得分:0)

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

Threads and Locks

Synchronization and thread safety in Java

答案 8 :(得分:0)

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