Search code examples
javaconcurrencyatomic

Synchronize write to two collections


I need to put some value to maps if it is not there yet. The key->value (if set) should always be in two collections (that is put should happen in two maps atomically). I have tried to implement this as follows:

private final ConcurrentMap<String, Object> map1 = new ConcurrentHashMap<String, Object>();
private final ConcurrentMap<String, Object> map2 = new ConcurrentHashMap<String, Object>();

public Object putIfAbsent(String key) {
    Object retval = map1.get(key);
    if (retval == null) {
        synchronized (map1) {
            retval = map1.get(key);
            if (retval == null) {
                Object value = new Object(); //or get it somewhere
                synchronized (map2) {
                    map1.put(key, value);
                    map2.put(key, new Object());
                }
                retval = value;
            }
        }
    }
    return retval;
}

public void doSomething(String key) {
    Object obj1 = map1.get(key);
    Object obj2 = map2.get(key);
    //do smth
}

Will that work fine in all cases? Thanks


Solution

  • A few problems:

    • Don't use "double-checked locking". A quick Google search will reveal tons of articles which explain the problems with this technique. Just check inside the synchronized block.
    • You don't need to synchronize on both map1 and map2. Just use one or the other.
    • Synchronize within doSomething. Make sure you synchronize on the same object which is used for synchronization in putIfAbsent.