A red herring. Reason: body of externalToInternal method would still need to be wrapped in this.synchronized { ... }, because ConcurrentHashMap can't prevent two threads T1 and T2 from both calling externalToInternalMap.size, then both proceeding to insert different externalNodeId keys into the map in the getOrElseUpdate call. My unit tests catch this race condition if I simply switch to ConcurrentHashMap and remove the synchronized block.
When critical section must be protected by an external mutex anyway, ConcurrentHashMap seems to have no advantage over HashMap unless I'm missing something.