views:

97

answers:

3

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?
+1  A: 

Is there a specific reason why Collections doesn't provide utility methods for NavigableMap?

I cannot think of a specific reason. It is either

  • an oversight,
  • a case of "hardly anyone would use it", or
  • maybe there is some technical difficulty that is not obvious.

But in either case, the reason doesn't really matter. The utility method is not there, so either you find a third-party library or implement it yourself.

Is it true that in general you can add synchronized thread-safetyness feature like this?

In general no. You need to understand the semantics of the class you are tying to make thread safe to figure out whether a wrapper is sufficient.

If it's such a mechanical process, can it be automated? (Eclipse plug-in, etc)

No ... see above.

Is this code repetition necessary, or could it have been avoided by a different OOP design pattern?

I don't think that it is avoidable. This kind of thing would require linguistic support for meta-programming in general, or for the specific case of writing wrapper classes. Design patterns don't do that kind of thing for you.

Stephen C
@Stephen: just to clarify my own understanding, though, is this the Decorator pattern that `Collections` does with regards to the wrapper classes? e.g. `synchronizedSet` returns a `Set` that "decorates" another `Set` with threat-safety feature, but itself doesn't do any `Set`-like work on its own?
polygenelubricants
@polygenelubricants I would say that is right.
Stephen C
+1  A: 

Is it true that in general you can add synchronized thread-safetiness feature like this?

I believe that is true. The definition of thread safety is (IMO),

A class is thread-safe if no incorrect behavior (that cannot occur when used from a single thread) can occur for all methods of it, when called from multiple-threads without any external synchronization.

Now, below code will ensure that "Something" is never called by multiple threads, right? Therefore, I believe no adverse behavior can emerge because of being called by multiple threads; It's never called from multiple threads!

This is probably also the idea behind EJB. Stateless EJBs are never called by more than one thread (enforced by the container). This is why the EJB spec can say "You don't have to worry about thread-safety".

public class MakeSomethingThreadSafe implements Something {
    private final Object lock = new Object();
    private final Something subject;

    public MakeSomethingThreadSafe(Something subject){
        this.subject = subject;
    }

    public void someMethod(){
        synchronized(lock){
            subject.someMethod();
        }
    }
}

Or am I missing something?

To make the post complete:

Is there a specific reason why Collections doesn't provide utility methods for NavigableMap?

I agree with Stephen.

How would you write your own synchronized wrapper for NavigableMap?

Like my sample code..

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)

Yeah I think it can easily be automated.

  1. Implement the interface
  2. Make 2 fields; One for the mutex, one for the subject.
  3. Create a constructor to inject subject.
  4. Make every method synchronized and delegate to subject.

Is this code repetition necessary, or could it have been avoided by a different OOP design pattern?

Like for Set, Map etc? It doesn't sound possible to me to solve it in a "normal" way..

Enno Shioji
+2  A: 

This was an oversight. The fix is in progress.

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

It takes a time though.

Update: as to manually implementing it, 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.

BalusC
Woot! As authoritative as it gets on the "why?". I can't accept this answer right now since it's missing the "how?", though. Would you kindly comment on that? It's still a big part of my question. How difficult is it to write and test these "mind-numbing forwarding methods"? Can it not be semi-automated? Etc.
polygenelubricants
I would just copy `static class SynchronizedMap` and `static class SynchronizedSortedMap` out of the `Collections` source, add your own `SynchronizedNavigableMap` which `extends SynchronizedSortedMap` and decorate the missing methods the same way as the two copied classes does. This going to be a lot of code and it's late :)
BalusC
@BalusC: it's such a mechanical and "mind numbing" process! One would think that it should be automatable!
polygenelubricants