我正在尝试解决间歇性故障,这种故障似乎与从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没有“同步”。
答案 0 :(得分:7)
删除/获取和放置之间略有不同(虽然我的猜测是你有线程问题)。
remove
/ get
的参数属于Object
类型;对于put
,它的类型为K
。其原因之前已多次说明。这意味着它有拳击问题。我甚至不会猜测规则是什么。如果某个值在一个地方被装箱为Byte
而在另一个地方被装箱Short
,则这两个对象不能相等。
List.remove(int)
和List.remove(Object)
存在类似问题。
答案 1 :(得分:6)
我认为,每当您检查项目是否存在时,您肯定会使用short
或Short argument
到Map.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)
已经在一些响应中提到过线程,但您是否考虑过多个线程使用的对象的可见性问题?如果你将一个对象放入一个线程的集合中,它就不会被“发布”到其他线程,除非你已经对集合进行了正确的同步,这是可能的(并且很常见)。
答案 8 :(得分:0)
正如其他人观察到的那样,您必须知道HashMap是否仅由一个Thread访问。 CollectionSpy 是一个新的分析器,可让您立即查找所有容器中执行任何访问的线程数。有关详细信息,请参阅www.collectionspy.com。