Search code examples
javadesign-patternscollectionssynchronizationwrapper

Writing a synchronized thread-safety wrapper for NavigableMap


java.util.Collections currently provide the following utility methods for creating synchronized wrapper for various collection interfaces:

Analogously, it also has 6 unmodifiedXXX overloads.

The glaring omission here are the utility methods for NavigableMap<K,V>. It's true that it extends SortedMap, but so does SortedSet extends Set, and Set extends Collection, and Collections have dedicated utility methods for SortedSet and Set. Presumably NavigableMap is a useful abstraction, or else it wouldn't have been there in the first place, and yet there are no utility methods for it.

So the questions are:

  • Is there a specific reason why Collections doesn't provide utility methods for NavigableMap?
  • How would you write your own synchronized wrapper for NavigableMap?
    • Glancing at the source code for OpenJDK version of Collections.java seems to suggest that this is just a "mechanical" process
      • Is it true that in general you can add synchronized thread-safetiness feature like this?
      • If it's such a mechanical process, can it be automated? (Eclipse plug-in, etc)
      • Is this code repetition necessary, or could it have been avoided by a different OOP design pattern?

Solution

  • This was an oversight. The fix was added in Java 8.

    Josh writes:

    "They definitely belong there. Their absence is unintentional.
    We should put them in as soon as possible."

    I agree, even though none of us engineers are looking forward to writing (and testing) all those mind-numbing forwarding methods. Posted Date : 2006-08-21 00:50:41.0


    In case you're not on Java 8 yet, you may consider to hijack the java.util package since you would like to extend static class SynchronizedSortedMap<K, V> which is declared package private. Else it's going to be a lot of code copypaste. Here's a kickoff:

    package java.util;
    
    import java.util.Collections.SynchronizedSortedMap;
    
    public class NewCollections {
    
        public static <K, V> NavigableMap<K, V> synchronizedNavigableMap(NavigableMap<K, V> m) {
            return new SynchronizedNavigableMap<K, V>(m);
        }
    
        static class SynchronizedNavigableMap<K, V> extends SynchronizedSortedMap<K, V> implements NavigableMap<K, V> {
            private final NavigableMap<K, V> sm;
    
            SynchronizedNavigableMap(NavigableMap<K, V> m) {
                super(m);
                sm = m;
            }
    
            SynchronizedNavigableMap(NavigableMap<K, V> m, Object mutex) {
                super(m, mutex);
                sm = m;
            }
    
        }
    }
    

    Let the IDE autogenerate the unimplemented methods of NavigableMap and code them the same way as SynchronizedSortedMap does. Here's ONE example:

            @Override
            public K ceilingKey(K key) {
                synchronized (mutex) { return sm.ceilingKey(key); }
            }
    

    Note that the methods which returns for example Set you'll need to wrap it in SynchronizedSet as well. Again, see the SynchronizedMap and SynchronizedSortedMap sources for insights :)

    I don't expect it to be (able to be) a mechanical process since it involves a lot of factors.