I am attempting to implement a class with the following features by wrapping one of the built in Map classes.
- Basic map functionality. (Only basic put, get, remove)
- Can iterate over the values of the map in the order they were added. (as in LinkedHashMap)
- Is thread safe.
Currently using a generic implementation but in the current use-case there will only ever be a handful of objects in the map. And additions/removal happen extremely infrequently - nominally additions occur only once.
Basically this one container should provide clients the ability to lookup a single Value object by Key AND/OR iterate through the Values (with order guarantee). In either case, the caller will likely be modifying the Value object, so it can't be read-only. Finally, callers may be coming from multiple threads.
This a minimized version of what I have right now:
public class MapWrapper<K, V> implements Iterable<V>
{
private Map<K, V> map = new LinkedHashMap<K, V>();
public void add(K key, V value)
{
// Does some other stuff
synchronized (map)
{
map.put(key, value);
}
}
public V get(K key)
{
V retVal;
synchronized (map)
{
retVal = map.get(key);
}
return retVal;
}
@Override
public Iterator<V> iterator()
{
List<V> values = new ArrayList<V>(map.values());
return values.iterator();
}
}
I feel like the iterator part is preventing this from being fully thread-safe. I see classes such as ConcurrentHashMap state that any client obtaining an iterator on the object MUST manually synchronize on the map object itself. Is there a way to make the code above thread-safe but still allow clients direct iterator access? Ie, I would like to be able to use a for-in loop, but I can not synchronize on the underlying map within MapWrapper.
MapWrapper<String, Object> test = new MapWrapper<String,Object>();
test.add("a", new Object());
test.add("c", new Object());
for (Object o: test) { o.setSomething(); }