Issue
Assuming a single server (no load balancer etc.), if a request in a Java servlet writes to a static ConcurrentHashMap
, is the map entry immediately available to all subsequent servlet requests until the entry is removed from the map? In order words is there any possibility that, after a write to the map has returned, a subsequent request from another servlet request could find nothing for the mapping? For example:
import java.util.concurrent.ConcurrentHashMap;
public class IntentTracker {
private static ConcurrentHashMap<String, AccountUpdateRequest> updateForIntent = new ConcurrentHashMap<>();
// static access only
private IntentTracker() {}
public static void put(String intentId, AccountUpdateRequest accountUpdate) {
updateForIntent.put(intentId, accountUpdate);
}
public static AccountUpdateRequest remove(String intentId) {
return updateForIntent.remove(intentId);
}
}
I know that the ideal situation here would be to use a persistent datastore for storage and retrieval, but I'd like to understand if the ConcurrentHashMap
would cause an issue here.
Solution
Assuming a single server (no load balancer etc.), if a request in a Java servlet writes to a static ConcurrentHashMap, is the map entry immediately available to all subsequent servlet requests until the entry is removed from the map?
One of the problems in multithreaded programming is defining "subsequent" and similar terms describing the ordering of events in time. Some of the relevant promises ConcurrentHashMap
makes are that
- All threads will perceive the same order of single-element map modifications.
- All threads will observe an order of single-element retrievals consistent with the order of modifications.
Iterator
s,Spliterator
s, andEnumeration
s of the map's contents will reflect a the state of the map at some specific point in time relative to the order of single-element modifications. (No promise is made that this point in time is tied to the instantiation of the iterator, etc..)
The specs do say ...
Retrievals reflect the results of the most recently completed update operations holding upon their onset.
... but that has to be taken as a statement of intent, not a specification. It is followed by this more formal expression of what that actually means:
an update operation for a given key bears a happens-before relation with any (non-null) retrieval for that key reporting the updated value
In practice, the intent is to provide the behavior you want to see, but it is more logically correct to look at it the other way around: in the absence of any other modifications, whether one thread's read action R perceives a particular modification W to the map performed by a different thread defines whether R happened before or after W.
In order words is there any possibility that, after a write to the map has returned, a subsequent request from another servlet request could find nothing for the mapping?
If we use the appropriate definition of "subsequent" then the answer is trivially "no", because whether a request is "subsequent" is defined by (among other things) whether one request sees the other's modification to the map. But if one thread does see that modification (or another that happened afterward in the globally-consistent order of modifications to the map), then it will also see all other actions on shared memory that the other performed before modifying the map.
That is not to imply that you have to fear a long delay before one thread's modifications to the map are visible to other threads. You do not. The timing and memory ordering considerations with respect to single-element operations are much the same as if you used an ordinary HashMap
and performed each update and each read under protection of a mutex, but normally no locking is involved with a ConcurrentHashMap
.
Answered By - John Bollinger