Skip to content

Instantly share code, notes, and snippets.

@kjetilv
Created September 14, 2010 08:40
Show Gist options
  • Save kjetilv/578732 to your computer and use it in GitHub Desktop.
Save kjetilv/578732 to your computer and use it in GitHub Desktop.
How to access concurrent map lazily and correctly?
/**
* <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() { }
}
@kjetilv
Copy link
Author

kjetilv commented Sep 14, 2010

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment