ConcurrentHashMap上的Java containsKey()对于Map中存在的UUID键返回false

mefy6pfw  于 2023-06-28  发布在  Java
关注(0)|答案(2)|浏览(100)

我正在使用类型的对象

Map<Long, Map<UUID, OperationEntry>> stepOperations = new ConcurrentHashMap<>();

以控制某些操作的执行。我有一个Kafka消息处理器方法,在接收到关于操作状态更改的消息时,需要根据传递的UUID在stepOperationsMap中查找和更新记录的状态。
UUID类未被覆盖(standatdjava.util.UUID)。
如果Map中存在screenshot中清晰可见的键“3102869 c-7653- 4fb 7-ad 47-a629 b5 cbac 90”,那么从containsKey方法中获得意外结果的原因是什么?
下面是代码中有问题的部分:

private OperationEntry getOperationLogEntry(UUID requestId) {
        return stepOperations.values().stream()
            .filter(value -> value.containsKey(requestId))
            .map(value -> value.get(requestId))
            .findFirst()
            .orElse(null);
    }

使用ConcurrentHashMap类是因为它保证支持多线程处理。传入的Kafka消息由一个由16个线程组成的线程池处理。
内部Map的存在会是一个潜在的问题吗?
简单测试,如

Map<UUID, String> testMap = new java.util.concurrent.ConcurrentHashMap<>();
        UUID key = UUID.randomUUID();
        testMap.put(key, "testValue");
        if (testMap.containsKey(key)) {
            System.out.println(testMap.get(key));
        }

就像预期的那样工作

col17t5w

col17t5w1#

在调试器中,我们可以看到HashMap中的value变量。不是ConcurrentHashMap

当你使用多级Map时,你应该使用computeIfAbsent
从你的代码中,你可能应该:

  • stepOperations成为ConcurrentMap<Long, ConcurrentMap<UUID, Whatever>>,以确保两个级别都是好的。
  • 使用computeIfAbsent,如stepOperations.computeIfAbsent(key, ignored -> new ConcurrentHashMap<>())
  • 确保Map本身不能从外部访问(Map可能会被污染)。

要添加新步骤,请执行以下操作:

stepOperations.computeIfAbsent(opId,  ignored -> new ConcurrentHashMap<>()))
              .put(opUUID, opWhatever)

最后,你可以重写你的代码:

stepOperations
   .values()
   .stream()
   .filter(value -> value.containsKey(operationRunState.requestId))
   .map(value -> value.get(operationRunState.requestId))
   .findFirst()

这样做,而不是:

var id = operationRunState.requestId;
stepOperations
   .values()
   .stream().map(value -> value.get(id))
   .filter(Objects::nonNull)
   .findFirst();

两点:

  • 使用局部变量id确保使用相同的id
  • ConcurrentHashMap禁止键和值为nullcontainsKey在这里是无用的。
jogvjijk

jogvjijk2#

感谢您的回复。事实上,取代

private final Map<Long, Map<UUID, OperationEntry>> stepOperations = new ConcurrentHashMap<>();

private final ConcurrentMap<Long, ConcurrentMap<UUID, OperationEntry>> stepOperations = new ConcurrentHashMap<>();

在这种情况下,内部Map也必须是并发的。

相关问题