itn*_*ick 1 java uuid concurrenthashmap
我正在使用类型的对象
Map<Long, Map<UUID, OperationEntry>> stepOperations = new ConcurrentHashMap<>();
Run Code Online (Sandbox Code Playgroud)
来控制一些操作的执行。我有一个 Kafka 消息处理程序方法,在收到有关操作状态更改的消息后,需要根据传递的 UUID 在 stepOperations 映射中查找并更新记录的状态。
UUID 类未被覆盖(标准 java.util.UUID)。
如果地图中存在密钥“3102869c-7653-4fb7-ad47-a629b5cbac90”(如屏幕截图所示),那么从 containsKey 方法获得意外结果的原因可能是什么?
这是代码中有问题的部分:
private OperationEntry getOperationLogEntry(UUID requestId) {
return stepOperations.values().stream()
.filter(value -> value.containsKey(requestId))
.map(value -> value.get(requestId))
.findFirst()
.orElse(null);
}
Run Code Online (Sandbox Code Playgroud)
使用 ConcurrentHashMap 类是因为它保证支持多线程处理。传入的 Kafka 消息由由 16 个线程组成的线程池进行处理。
内部地图的存在可能是这里的潜在问题吗?
简单的测试例如
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));
}
Run Code Online (Sandbox Code Playgroud)
按预期工作
在调试器中,我们可以value在HashMap. 不是ConcurrentHashMap:
当您使用多级别地图时,您应该使用computeIfAbsent.
从您的代码来看,您可能应该:
stepOperations确保ConcurrentMap<Long, ConcurrentMap<UUID, Whatever>>这两个级别都良好。computeIfAbsent如stepOperations.computeIfAbsent(key, ignored -> new ConcurrentHashMap<>())要添加新步骤:
stepOperations.computeIfAbsent(opId, ignored -> new ConcurrentHashMap<>()))
.put(opUUID, opWhatever)
Run Code Online (Sandbox Code Playgroud)
最后,您可能可以重写您的代码:
stepOperations
.values()
.stream()
.filter(value -> value.containsKey(operationRunState.requestId))
.map(value -> value.get(operationRunState.requestId))
.findFirst()
Run Code Online (Sandbox Code Playgroud)
这样做:
var id = operationRunState.requestId;
stepOperations
.values()
.stream().map(value -> value.get(id))
.filter(Objects::nonNull)
.findFirst();
Run Code Online (Sandbox Code Playgroud)
两点:
id来确保使用相同的 idConcurrentHashMap禁止 key 和 value 存在null:containsKey这里没有用。