如果我希望使用的密钥保证是唯一的(或者至少可以假设密钥是唯一的),那么使用'vanilla'ConcurrentHashMap可以提供最佳性能,还是需要修改散列函数或put方法以避免不必要的散列?
此外,数字键是否比非数字键具有任何性能优势(例如具有适当散列函数的String或POJO)?
答案 0 :(得分:7)
正如评论中已经提到的,如果您不需要线程安全方面,请不要使用ConcurrentHashMap
。
如果您希望获得绝对最佳性能,请考虑实习您的密钥并使用IdentityHashMap。这避免了计算对象的哈希值(并且,如评论中所述,否定了对equals
进行求值的需要),而是假设引用本身就是哈希值。
请注意,您必须确保同一个键的两个实例是同一个对象(例如,您必须确保引用相等,而不仅仅是对象相等)。实习所有密钥是实现这一目标的一种方法。
实施说明:这是一个简单的线性探测哈希表,如Sedgewick和Knuth的文章中所述。阵列交替显示保持键和值。 (对于大型表,这比使用单独的数组具有更好的局部性。)对于许多JRE实现和操作混合,此类将产生比HashMap更好的性能(HashMap使用链接而不是线性探测)。
如果您知道所有密钥,也许您也可以考虑perfect hashing?或映射到一个简单的数组结构?
答案 1 :(得分:1)
ConcurrentHashMap是HashMap实现中最昂贵的,这是因为它是线程安全的。
所有地图必须具有唯一键,因此这是给定的。
如果使用支持TLongHashMap等原始数据的集合,则使用数字具有性能优势,但使用自定义哈希映射可能会更快。
来自http://vanillajava.blogspot.com/2011/07/low-gc-in-java-using-primitives.html
Test Performance Memory used
Use Integer wrappers and HashMap 71 - 134 (ns) 53 MB/sec
Use int primitives and HashMap 45 - 76 (ns) 36 MB/sec
Use int primitives and FastMap 58 - 93 (ns) 28 MB/sec
Use int primitives and TIntIntHashMap 18 - 28 (ns) nonimal
Use int primitives and simple hash map 6 - 9 (ns) nonimal
答案 2 :(得分:1)
如果我希望使用的密钥保证是唯一的(或者至少可以假设密钥是唯一的),那么使用'vanilla'ConcurrentHashMap可以提供最佳性能,
如果ConcurrentHashMap
是潜在的并发瓶颈,通常会使用Map
。如果您的应用程序是单线程的,或者没有争用,ConcurrentHashMap
比HashMap
慢。
或者是否需要修改散列函数或put方法以避免不必要的散列?
散列函数每哈希表的“探测”得到一次评估;例如每get
或put
次操作一次。您可以通过缓存结果来降低散列函数的成本,但这会使每个密钥对象额外增加4个字节的存储空间。缓存是否值得进行优化取决于:
hashCode()
调用的比例。这两个因素都是高度针对特定应用的。
(顺便说一句,使用身份哈希码作为哈希值的长期成本也额外的4个字节的存储空间。)
此外,数字键是否比非数字键具有任何性能优势(例如具有适当散列函数的String或POJO)?
哈希函数在数值情况下可能更便宜,但它是否值得,取决于是否存在使用数字键的特定于应用程序的缺点。而且,如上所述,相对成本是应用程序细节。例如,String.hashCode()
的成本与被散列的字符串的长度成正比。
答案 3 :(得分:0)
Java的HashMaps最终由Entry<K,V>
数组支持,其中K的哈希码用于确定存储Entry的数组中的插槽。
所使用的数组的大小(通常从16开始)远小于可能的哈希码(2 ^ 32~ = 40亿)的数量,因此即使哈希码是哈希码,也必然会在此数组中发生冲突。唯一的。
只要你的hashcode()方法很快,用作Key的类型就没有区别。请记住,hashcode()方法可能被称为 lots 次,所以如果它很慢,你可以在内部将它缓存在对象中。
答案 4 :(得分:0)
我有ConcurrentHashMap实例映射,可通过multithread.seeing在代码片段下访问。这些怎么样?
Iterator<String> it = new TreeSet<String>(map.keySet()).iterator();
while(it.hasNext())
{
id = it.next();
synchronized(map)
{
msg = map.get(id);
if(msg != null)
map.remove(id);
}
if(msg != null)
listener.procMessage(msg);
}