javauuidconcurrenthashmap

Java containsKey() on ConcurrentHashMap returns false for a UUID key that present in the map


I am using an object of type

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

to control the execution of some operations. I have a Kafka message handler method that, upon receiving a message about a status change of an operation, needs to find and update the state of a record in stepOperations map based on the passed UUID.

UUID class is not overriden (standatd java.util.UUID).

What could be the reason for getting an unexpected result from the containsKey method if the key "3102869c-7653-4fb7-ad47-a629b5cbac90", as clearly seen in the screenshot, is present in the map?

Here is the problematic part of the code:

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

The ConcurrentHashMap class is used due to its guaranted support for multithreaded processing. The incoming Kafka messages are processed by a thread pool consisting of 16 threads.

Could the presence of a inner map be a potential issue here?

Simple test such as

        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));
        }

works as it's expected to be


Solution

  • In the debugger, we can see that value variable in an HashMap. Not a ConcurrentHashMap:

    HashMap

    When you work with multi levels of map, you should use computeIfAbsent.

    From your code, you should probably:

    To add a new step:

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

    Finally, you could probably rewrite your code:

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

    Do that instead:

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

    Two points: