Hi tsuna,

Changing this class to use ConcurrentHashMap, and completely removing
synchronization, won't work, as it's written. The lazy-loading in
regionCachePreFetchEnabled() (get - if null, put) won't work correctly with
a ConcurrentHashMap without external synchronization.

I'm not sure to understand why, can you explain?

No problem. With that change, there would be a potential race condition:

Thread 1                                Thread 2
----------                              -------------
enter regionCachePrefetchEnabled
call ConcurrentMap.get() - get null
                                        enter disableRegionCachePrefetch
                                        ConcurrentMap.put(false);
                                        exit disableRegionCachePrefetch
ConcurrentMap.put(true)
exit regionCachePrefetchEnabled


which means that after one (nominally 'read-only') call to regionCachePrefetchEnabled and one call to disableRegionCachePrefetch have completed, the value in the cache for the table is true, when it really should be false.

The get-nullcheck-put triad really needs to be atomic, which requires either external synchronization or use of some of the other features of ConcurrentHashMap like below.

Slide 31 of the aforementioned presentation reads "Calls putIfAbsent
every time it needs to read a value" "Unfortunately, this usage is
very common" so I think this is not a good idea.

I'm still fairly new to Java so I tend to trust what people like
Joshua Bloch write, but I can be convinced otherwise :)

That's purely for performance reasons -- you're right, I should have suggested
   get, if (result == null) {putIfAbsent, get}
rather than
   putIfAbsent, get

Both are correct but as Josh talks about on that slide (and the subsequent one) it's needless contention. I would be almost certain that it's still faster than a synchronized block, but not as much as other options. Should have mentioned that.

Of the 4 options I mentioned (putIfAbsent(), get() and default return value if missing, CopyOnWriteArraySet, ConcurrentHashSet), the putIfAbsent() method is likely the slowest (given the usage pattern anyway), and (more importantly, in my opinion) the least clear anyway. I think the ConcurrentSet solution is much cleaner.

Hope that makes thing clear.

Cheers,

Paul

Reply via email to