VB_
VB_

Reputation: 45702

Java map: multithreading juggler

I faced the next problems:

  1. I have many asynchronous readers and writers. Has jdk got any implementation that provide thread safety for my case? As I understand ConcurrentHashMap isn't appropriate for situation when there are many asynch writers.
  2. If I need to synchronize two concurrent maps between each other, can I achieve that without full synchronization? (I mean without adding synchonized keyword at each method)

I read your comments and decided to reformulate my question.

Imagine situation, you have to concurrent maps:

//Singleton
public class Container {
   public ConcurrentHashMap<String, MyObj> map1 = new ConcurrentHashMap<String, MyObj>();
   public ConcurrentHashMap<String, MyObj> map2 = new ConcurrentHashMap<String, MyObj>();

   public void replaceForward(String key) {
     Object value = map1.remove(key);
     map2.put(key, value);
   }

   public void replaceBackward(String key) {
     MyObj value = map2.remove(key);
     map1.put(key, value);
   }

   //This operation should be as quick as possible!
   public void replaceAllForward(int criteria) {
     for (Map.Entry<String, MyObj> entry entry : map1.entrySet()) {
       if (entry.getValue().criteria = criteria) {
         replaceForward(entry.getKey()); 
       }
     }
   }

   //This operation should be as quick as possible!
   public void replaceAllBackward(String key) {
     //just the same but from map2 to map1
   }

   public void remove(String key) {
      map1.remove(key);
   }

   public void add(String key, MyObj value) {
      map2.put(key, value);
   }

   //This operation should be as quick as possible!
   public Map<String, MyObj> getByCriteria(int criteria) {
     ConcurrentHashMap<String, MyObj> resultMap = new ConcurrentHashMap<String, MyObj>();
     for (Map.Entry<String, MyObj> entry entry : map1.entrySet()) {
       if (entry.getValue().criteria = criteria) {
         resultMap.put(entry.getKey(), entry.getValue); 
       }
     }
     return resultMap;
   }
}

And you have two threads, both operates with those maps.

Thread1: replaces elements from map1 to map2 (i mean removes from map1 and puts to map2)

Thread1: replaces elements from map2 to map1

Question: Is it thread safe?

Upvotes: 0

Views: 202

Answers (1)

assylias
assylias

Reputation: 328737

With ConcurrentHashMap like in your example and if you write:

V value = map1.remove(key);
if (value != null) map2.put(key, value);

you have the guarantee that no item will get "lost" and no item will be added to map2 more than once, even in the presence of multipler readers/writers.

However there is going to be a short time during which the key/value will not be in map1 or map2. This may or may not be a problem for your use case.

In your replaceAllForward you iterate over one map and move the content to the other map. Here again, the move will happen safely, but there may be some items left in the original map at the end if they have been added in the meantime.


How to make getAllByCriteria faster?

It depends on the size of your map. If it's small-ish, you probably can't do much better. If it is larger, you can parallelise the job.

With Java 8, you could probably get a better performance with something like:

public Map<String, MyObj> getByCriteria(int criteria) {
  return map1.entrySet()
      .parallelStream() //this is your speedup
      .filter(e -> e.getValue().criteria = criteria)
      .collect(toConcurrentMap(Entry::getKey, Entry::getValue));
}

Prior to Java 8, you could write the parallel algo yourself and see if it improves the performance.

Upvotes: 1

Related Questions