Created
September 14, 2010 08:40
-
-
Save kjetilv/578732 to your computer and use it in GitHub Desktop.
How to access concurrent map lazily and correctly?
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* <p>A suggested usage pattern (actually a util class) for a map that:</p> | |
* | |
* <ul> | |
* <li>is accessed by many threads</li> | |
* <li>should construct new values lazily as keys are requested</li> | |
* <li>should construct each value once and only once</li> | |
* </ul> | |
* | |
* <p>I think it works. Comments welcome.</p> | |
* @author kjetilv | |
*/ | |
import java.util.concurrent.ConcurrentHashMap; | |
import java.util.concurrent.ConcurrentMap; | |
public abstract class ConcurrentMapGatekeeper<K, V> { | |
private final ConcurrentMap<K, V> map; | |
private final V placeholder; | |
protected ConcurrentMapGatekeeper(V placeholder) { | |
this(null, placeholder); | |
} | |
protected ConcurrentMapGatekeeper(ConcurrentMap<K, V> map, V placeholder) { | |
this.map = map == null ? new ConcurrentHashMap<K, V>() : map; | |
this.placeholder = placeholder; | |
} | |
public final V get(K key) { | |
while (true) { | |
V value = map.get(key); | |
if (value != null && value != placeholder) { | |
return value; | |
} | |
V contestedValue = map.put(key, placeholder); | |
if (contestedValue == null) { | |
map.replace(key, placeholder, newValue(key)); | |
} | |
sleep(); | |
} | |
} | |
protected abstract V newValue(K key); | |
protected void sleep() { } | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Notes: Ignore the sleep() stuff, it's not important.
On closer inspection, the call to replace can be done with a simple put instead. So the gatekeeper can take any Map with atomic put and get. Yay it.