Is ConcurrentHashMap.get()
guaranteed to see a previous ConcurrentHashMap.put()
by different thread? My expectation is that is is, and reading the JavaDocs seems to indicate so, but I am 99% convinced that reality is different. On my production server the below seems to be happening. (I've caught it with logging.)
Pseudo code example:
static final ConcurrentHashMap map = new ConcurrentHashMap();
//sharedLock is key specific. One map, many keys. There is a 1:1
// relationship between key and Foo instance.
void doSomething(Semaphore sharedLock) {
boolean haveLock = sharedLock.tryAcquire(3000, MILLISECONDS);
if (haveLock) {
log("Have lock: " + threadId);
Foo foo = map.get("key");
log("foo=" + foo);
if (foo == null) {
log("New foo time! " + threadId);
foo = new Foo(); //foo is expensive to instance
map.put("key", foo);
} else
log("Found foo:" + threadId);
log("foo=" + foo);
sharedLock.release();
} else
log("No lock acquired");
}
What seems to be happening is this:
Thread 1 Thread 2
- request lock - request lock
- have lock - blocked waiting for lock
- get from map, nothing there
- create new foo
- place new foo in map
- logs foo.toString()
- release lock
- exit method - have lock
- get from map, NOTHING THERE!!! (Why not?)
- create new foo
- place new foo in map
- logs foo.toString()
- release lock
- exit method
So, my output looks like this:
Have lock: 1
foo=null
New foo time! 1
foo=foo@cafebabe420
Have lock: 2
foo=null
New foo time! 2
foo=foo@boof00boo
The second thread does not immediately see the put! Why? On my production system, there are more threads and I've only seen one thread, the first one that immediately follows thread 1, have a problem.
I've even tried shrinking the concurrency level on ConcurrentHashMap to 1, not that it should matter. E.g.:
static ConcurrentHashMap map = new ConcurrentHashMap(32, 1);
Where am I going wrong? My expectation? Or is there some bug in my code (the real software, not the above) that is causing this? I've gone over it repeatedly and am 99% sure I'm handling the locking correctly. I cannot even fathom a bug in ConcurrentHashMap
or the JVM. Please save me from myself.
Gorey specifics that might be relevant:
- quad-core 64-bit Xeon (DL380 G5)
- RHEL4 (
Linux mysvr 2.6.9-78.0.5.ELsmp #1 SMP
...x86_64 GNU/Linux
) - Java 6 (
build 1.6.0_07-b06
,64-Bit Server VM (build 10.0-b23, mixed mode)
)