This discussion is archived
1 2 Previous Next 16 Replies Latest reply: Nov 8, 2012 11:10 PM by Kayaman RSS

synchronized map

800347 Newbie
Currently Being Moderated
Hi folks,

I need to synchronize the elements in the map depending on the key. If 2 threads calling getID(ID_0), and setID(ID_2, System.currentTimeMillis()), will the synchronized block not to block setID while getID is calling.


private final String ID_0 = "0";
private final String ID_1 = "1";
private final String ID_2 = "2";

private final static Map<String, Calendar> ID_MAP = new HashMap<String, Calendar>(2);
private static Calendar getID(final String id) {
synchronized (id) {
Calendar calendar = ID_MAP.get(id);
if (calendar == null) {
ID_MAP.put(id, calendar);
}
return ID_MAP.get(id);
}
}

private static void setID(final String id, long millis) {
synchronized (id) {
Calendar calendar = ID_MAP.get(id);
if (calendar == null) {
calendar = Calendar.getInstance();
}
calendar.setTimeInMillis(millis);
ID_MAP.put(id, calendar);
}
}


Billy
  • 1. Re: synchronized map
    EJP Guru
    Currently Being Moderated
    They won't block each other as long as the ID is different, but this code won't work. You must either synchronise on the HashMap, which destroys your objective, or else use a ConcurrentHashMap, which doesn't destroy it. However the operations you are protecting are so quick that I don't believe your original objective is necessary, and that synchronising on the HashMap is sufficient.
  • 2. Re: synchronized map
    800347 Newbie
    Currently Being Moderated
    You mean even the id initialized as a final static String, and I mark it as final in the method param , it still will not doing the job? I just make a simple example. In fact, there are more code inside the synchronized block.
  • 3. Re: synchronized map
    Kayaman Guru
    Currently Being Moderated
    evebill8 wrote:
    You mean even the id initialized as a final static String, and I mark it as final in the method param
    The final modifier has nothing to do with this.
    it still will not doing the job?
    No. A cute idea, but one that won't work. And like EJP already said, it's unlikely that you need this. Have you profiled your application and noticed that this HashMap access is a bottleneck?
  • 4. Re: synchronized map
    EJP Guru
    Currently Being Moderated
    HashMap is not thread safe. If you don't synchronise on it, or on its containing object, etc., neither is your code.
  • 5. Re: synchronized map
    800347 Newbie
    Currently Being Moderated
    I just want to protect the Calendar object in the map, not the map. The map is only a container to me. If I synchronize the whole map every time update one of the entry in the map. Do you think it is efficient?
  • 6. Re: synchronized map
    DrClap Expert
    Currently Being Moderated
    If you aren't changing the map, then it's a red herring for your question. If you want to prevent simultaneous modifications of a Calendar object, then the logical approach would be to synchronize on that Calendar object. The fact that you happen to have a map entry which contains a reference to the object shouldn't have anything to do with it.
  • 7. Re: synchronized map
    800347 Newbie
    Currently Being Moderated
    How can I synchronize just the Calendar object? It is not a final object, and the IDEA will complain about it.
  • 8. Re: synchronized map
    DrClap Expert
    Currently Being Moderated
    I don't understand the question.

    For one thing there's no such thing as a "final object". There are final variables, but not final objects. And you synchronize on objects, not on variables.

    So if you want to synchronize on an object, you get a reference to the object and use that in your "synchronize" phrase:
    Calendar cal = // get a reference to your Calendar object
    synchronized(cal) {
      // code which modifies the object goes here
    }
  • 9. Re: synchronized map
    EJP Guru
    Currently Being Moderated
    I just want to protect the Calendar object in the map
    So synchronise on it! You aren't protecting it at all by what you're doing here.
    not the map.
    You don't get to choose. You must synchronise on the map, unless it happens to be read-only, which you haven't stated.
    The map is only a container to me.
    I don't know what that's supposed to mean, but it doesn't relieve you of having to synchronise on it.
    If I synchronize the whole map every time update one of the entry in the map. Do you think it is efficient?
    I have already answered precisely that question.
  • 10. Re: synchronized map
    800347 Newbie
    Currently Being Moderated
    Thank you all!
  • 11. Re: synchronized map
    966867 Newbie
    Currently Being Moderated
    Map is really very efficient, thus in this case a simple global lock is enough. But if you have similar case where read and write operations takes more time then it could be useful to take a look at ReadWriteLock or MultiLock.

    http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/ReadWriteLock.html
    https://sourceforge.net/p/happy-guys/wiki/MultiLock-MultiSynchronization/

    Take a look at your example below rewritten with MultiLock:
    package org.happy.examples.synchronizers;
    
    import java.util.Calendar;
    import java.util.Map;
    import java.util.concurrent.ConcurrentHashMap;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    import org.happy.commons.generators.Generators_1x3;
    import org.happy.commons.patterns.Generator_1x0;
    import org.happy.commons.patterns.executable.Executable_1x2;
    import org.happy.concurrent.Synchronizers_1x3;
    import org.happy.concurrent.synchronizers.MultiLock_1x3;
    import org.happy.concurrent.synchronizers.MultiLock_1x3.Permission_1x3;
    import org.happy.concurrent.synchronizers.Synchronizer_1x3;
    
    /**
     * 
     * @author Andreas Hollmann
     *
     */
    public class SynchroizedKeyExample {
    
    
    
         private final static Map<String, Calendar> ID_MAP = new ConcurrentHashMap<String, Calendar>();
    
         private static Synchronizer_1x3<Object> synchronizer = Synchronizers_1x3.newFIFOSynchronizer();
         
         
         /*
          * locks id with Read access in parallel, this method can be accessed by many threads concurrently, because it doesn't modify data.
          * This method can't be executed concurrently to setID because setID modifies data and requires Write access to the data
          */
         private static Calendar getID(final String id) {
              return synchronizer.synchronize(     id, Permission_1x3.Read, 
                                                           new Executable_1x2<Calendar, MultiLock_1x3<Object>>(){
                             @Override
                             public Calendar execute(MultiLock_1x3<Object> key) {
                                  if (!ID_MAP.containsKey(key)) {
                                       return null;
                                  }
                                  return ID_MAP.get(id);
                             }
                        } );
         }
    
         /*
          * locks id with Write access and map with read access, thus other id's can be read from the map.
          */
         private static void setID(final String id, final long millis) {
              
              synchronizer.synchronize(     id, Permission_1x3.Write, 
                        new Executable_1x2<Void, MultiLock_1x3<Object>>() {
                             @Override
                             public Void execute(MultiLock_1x3<Object> key) {
                                  Calendar calendar = ID_MAP.get(id);
                                  if (calendar == null) {
                                       calendar = Calendar.getInstance();
                                  }
                                  calendar.setTimeInMillis(millis);
                                  ID_MAP.put(id, calendar);                              
                                  return null;
                             }
                        });
              
         }
    
         /**
          * @param args
          */
         public static void main(String[] args) {
              
              final String ID_0 = "0";
              final String ID_1 = "1";
              final String ID_2 = "2";
              //generates random id from input array
              final Generator_1x0<String> g = Generators_1x3.arrayRandomObjectGenerator(new String[]{ID_0, ID_1, ID_2});
              
              final ExecutorService executor = Executors.newCachedThreadPool();
              
              //write
              for(int i=0; i<1; i++){
                   executor.execute(new Runnable() {
                        @Override
                        public void run() {
                             //gets id's
                             for(int j=0; j<(int)1e5; j++){
                                  String id = g.generate();
                                  long millis = System.currentTimeMillis();
                                  setID(id, millis);
                             }
                        }
                   });
              }
              
              //read
              for(int i=0; i<10; i++){
                   executor.execute(new Runnable() {
                        @Override
                        public void run() {
                             //gets id's
                             for(int j=0; j<(int)1e5; j++){
                                  String id = g.generate();
                                  getID(id);
                             }
                        }
                   });
              }
              
              executor.shutdown();
         }
    }
    Best Regrads
    Andrej
  • 12. Re: synchronized map
    800347 Newbie
    Currently Being Moderated
    Thank you very much!
  • 13. Re: synchronized map
    Kayaman Guru
    Currently Being Moderated
    zarr wrote:
    Take a look at your example below rewritten with MultiLock:
    A fine example indeed and a great way to shamelessly promote your library, but the OP had problems with the basics of concurrency and synchronization, something that can't be fixed by just throwing a library at them.
  • 14. Re: synchronized map
    966867 Newbie
    Currently Being Moderated
    Kayaman wrote:a great way to shamelessly promote your library
    Why promote? It's open source and I don't develop it alone!
    Kayaman wrote:a great way to shamelessly promote your library
    If you see any problems in MultiLock please tell me, I whould like to discuss them. I just want find out the method how to develop software without deadlocks. And such use cases in forums is a posibility find the truth :)

    Best Regards
    Andreas
1 2 Previous Next

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points