views:

537

answers:

5

What is the difference between a Collections.synchronizedMap() and a wrapper around a HashMap with all the methods synchronized. I dont see any difference becuase Collections.synchronizedMap() internally maintains the same lock for all methods.

Basically, what is the difference between the following code snippets

Class C {    
    Object o;

    public void foo() {
       synchronized(o) {
           // thread safe code here
       }
    }
}

and

Class C {
    Object o;

    public synchronized void foo() {

    }
}
A: 

You should always decorate rather than lumping everything and all feartures into one big featured class.

Always take the plain Map and decorate it with Collections or use a java.util.concurrent and use a real lock, so one can atomically inspect and update the map. Tomorrow you might want to change the Hashtable to a Treemap and you will be in trouble if your stuck with a hashtable.

mP
A: 

So, why do you ask? :) Do you really believe that if class is placed in java.util package then some magic happens and its java code works in some tricky way?

It really just wraps all methods with synchronized {} block and nothing more.

UPD: the difference is that you have much less chances to make a mistake if you use synchronized collection instead of doing all synchronization stuff by yourself.

UPD 2: as you can see in sources they use 'mutex'-object as monitor. When you use synchronized modifier in method signature (i.e. synchronized void doSmth()) current instance of your object (i.e. this) is used as a monitor. Two blocks of code below are the same:

1.

synchronized public void doSmth () {
   someLogic ();
   moreLogic ();
}

synchronized public static void doSmthStatic () {
   someStaticLogic ();
   moreStaticLogic ();
}

2.

public void doSmth () {
   synchronized (this) {
      someLogic ();
      moreLogic ();
   }
}

public static void doSmthStatic () {
   synchronized (ClassName.class) {
      someStaticLogic ();
      moreStaticLogic ();
   }
}
Roman
I just wanted to know if the behavior would have been any different had all the methods been declared synchronized instead of the synchronized block
java_geek
Actually, if you see the source code of SynchronizedMap, they are using synchronized blocks for all the methods. The entire code in the method is synchronized. How different is it from just making the method itself synchronized? This is what i wanted to know
java_geek
+3  A: 

There is only one difference:

Collections.synchronizedMap is able to use a different monitor than itself.

Using synchronized methods is the same as using sychnchonized(this)-blocks, which means, the wrapper would be the monitor and could be locked from the outside of the wrapper.

If you doesn't want an outside application to lock your monitor, you need to hide it.

On the other side, if you want to call multiple methods in a thread safe fashion, it is the easiest way to lock the whole collection (but it's not very scaleable, indeed).

Ps: For reuse, it's better to delegate the method calls to a backup-Map than to override the class, because you can switch to another Map implementation later, without changing your wrapper.

Hardcoded
Performance wise, will they be the same?
java_geek
Yes, they both will perform badly ;-)
Hardcoded
A: 

Do not reinvent the wheel and use what is provided by the API.

chburd
i am not re-iventing. I am just trying to understand if both approaches work the same way and with same performance. What are the advantages/disadvantages of one over the other
java_geek
+1  A: 

Both approaches acquire a monitor on the object and so should perform exactly the same. The main reason for the difference is architectural. The synchronized wrapper allows extending the basic non-thread safe variation easily.

Having said that don't use either, use ConcurrentHashMap. It uses lock striping so it's much quicker to use than either approach (as they are the same in terms of overhead + contention). Lock striping allows segments of the backing array to be locked independently. This means it's less probable that two threads will request to acquire the same lock.

reccles
+1 for being the only person to mention lock striping on this answer. However, there are times where that's not the best answer - e.g. ConcurrentHashMap's iterator is failFast (will fail with concurrentmodificationException on change while iterating) while you might actually need a locked iterator for some uses.
Steve B.
That's true, good point. I suppose everything has a caveat.
reccles