开发者

Collection.synchronizedMap vs synchronizing individual methods in HashMap

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() {

    }
}


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.


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.


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


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.


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 ();
   }
}


If thread safety is the case, use concurrency package data structures. Using the wrapper class will reduce all accesses to the Map into a sequential queue.

a) Threads waiting to do operations at totally different points in the Map will be waiting for the same lock. Based on the number of threads this can affect the application performance.

b) Consider compound operations on the Map. Using a wrapper with a Single lock will not help. For example. "Look if present then add" kind of operations. Thread syncronization will again become an issue.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜