1 2 Previous Next 16 Replies Latest reply: Nov 9, 2012 1:10 AM by Kayaman RSS

    synchronized map

    800347
      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
          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
            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
              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
                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
                  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
                    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
                      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
                        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
                          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
                            Thank you all!
                            • 11. Re: synchronized map
                              966867
                              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
                                Thank you very much!
                                • 13. Re: synchronized map
                                  Kayaman
                                  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
                                    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