【问题标题】:putIfAbsent() not working with ConcurrentHashMapputIfAbsent() 不适用于 ConcurrentHashMap
【发布时间】:2013-10-01 19:55:12
【问题描述】:
public static void main(String args[]) throws Exception {
    ConcurrentHashMap<byte[], Integer> dps =
         new ConcurrentHashMap<byte[], Integer>();

    System.out.println(dps.putIfAbsent("hi".getBytes(), 1));
    System.out.println(dps.putIfAbsent("hi".getBytes(), 1));
}

打印

null
null

为什么不在第二行打印1?我已经阅读了putIfAbsent 的语义,应该保证它可以工作。 (注意:这是从一个大型并发程序中提炼出来的……如您所见,它现在是单线程的。)

【问题讨论】:

    标签: java concurrency hashmap concurrenthashmap


    【解决方案1】:

    putIfAbsent() 不适用于 ConcurrentHashMap

    "hi".getBytes() 不是一个常量数组,因此您在那里生成两个不同的对象。如果您执行以下操作,您将看到您的1

    byte[] bytes = "hi".getBytes();
    System.out.println(dps.putIfAbsent(bytes, 1));
    System.out.println(dps.putIfAbsent(bytes, 1));
    

    byte[] 数组上的hashCode()equals(...) 方法来自Object,它只查看对象的引用,而不查看其内容。

    每当您将某些内容存储在 Map 中时,您需要确保它覆盖 hashCode()equals(...) 方法,除非您只想比较引用。这是一个 Java 常见问题解答。请参阅这些文档:Java theory and practice: Hashing it out

    正如@Mauren 在 cmets 中提到的,要使用byte[]内容,您将不得不编写一个小类来包装byte[] 并提供正确的hashCode() 和@ 987654336@ 方法。或者正如@CostiCiudatu 提到的那样,您可以使用SortedMap 并为byte[] 使用Comparator,它会查看数组的内容。

    顺便说一句,如果String.getBytes() 返回一个new byte[],则根据您的字符集等使用StringCoding.StringEncoder 类进行编码。

    【讨论】:

    • 刚刚注意到如果我将byte[] 更改为String(当然还删除了getBytes()),那么我会得到预期的行为。但是我的Strings 是不同的对象,所以按照你的逻辑它不应该工作。还是我听不懂?
    • 好的,根据您的新编辑,我了解:String 比较内容,但 byte[] 比较参考。非常不直观。因此,似乎使用 byte[] 作为 Map 键通常不是一个好主意。
    • @Fixee String 已覆盖 equals()hashCode() 方法,这就是它与 String 正常工作的原因。
    • 每当您在Map 中存储某些内容时,您需要确保它覆盖equals/hashCode,除非您只想比较引用@Fixee。 Java 常见问题解答:ibm.com/developerworks/java/library/j-jtp05273/index.html
    • 或者您可以将SortedMap(例如TreeMap)与Comparator 一起用于字节数组。这种方法在 HBase 中使用,它适用于为每个字节数组创建包装对象过于昂贵的情况。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-31
    • 2014-06-27
    • 1970-01-01
    • 2015-12-26
    • 2020-11-24
    相关资源
    最近更新 更多