简体   繁体   中英

Should I use synchronized block for this simple case?

Say I have a Resource class which holds a Map type resources object:

public class Resource {
   private Map<Integer, MyResource> resources = new HashMap<Integer, MyResource>();

   public void addResource(MyResource r){
     synchronized(resources){
        resources.put(r.getId(), r);
     }
   }

   public void removeResource(int id){
      synchronized(resources){
            resources.remove(id);
      }
   }

}

Since multiple threads could access the resources , so I always use synchronized block for adding new resource & removing existing resource like the code shows above.

Now, I would also like to add a function to get all the current resources, my question is very simple, that's should I use synchronized block too to return all the current resources or is it worthless to use synchronized block ?

public Map<Integer, MyResource> getResources(){
     return resources;
}

Is it enough to use above code to return current resources, or is it still beneficial to use synchronized block as below:

public Map<Integer, MyResource> getResources(){
   synchronized(resources){
       return resources;
   }
}

Personally, I feel that it doesn't worth to use synchronized block for getting resources since it always return the current moment resources. But I am not sure. So, it would be nice if you could explain to me the reason whether to use synchronized block or not, thanks.

Is it enough to use above code to return current resources, or is it still beneficial to use synchronized block as below

Neither is enough. It matters little whether you return the reference to the shared map within or without the synchronized block: you must do all the reading actions within a synchronized block. In fact, you should never allow the reference to the map escape your object because then it will be on the loose, with no enforceable synchronization policy.

If you just return resources it means that anyone calling the method will get full and unsynchronized access to it. That is, the caller can add and remove items to the map without telling you and without synchronizing access with other threads. This is probably a bad idea.

The safest thing you can do is create a defensive copy while holding the lock on resources :

public Map<Integer, MyResource> getResources(){
   synchronized(resources){
       return new HashMap<Integer, MyResource>(resources);
   }
}

Update: An alterative is using Collections.synchronizedMap ConcurrentHashMap to ensure all accesses are thread safe, and then return an unmodifiable view so that code calling getResources cannot modify the map you use internally.

Update 2: Don't use Collections.synchronizedMap for this: iterating on the map would require synchronizing on it, and if getResources returns an unmodifiable view there's no way the calling code can do that.

// Don't use synchronizedMap
// private Map<Integer, MyResource> resources = Collections.synchronizedMap(new HashMap<Integer, MyResource>());

private Map<Integer, MyResource> resources = new ConcurrentHashMap<>();

public void addResource(MyResource r) {
    resources.put(r.getId(), r);
}

public void removeResource(int id) {
    resources.remove(id);
}

public Map<Integer, MyResource> getResources() {
    return Collections.unmodifiableMap(resources);
}

由于您只需要读取数据,因此您也可以使用不synchronized简单方法。由于从remove方法中脏数据存在于映射中的唯一可能性是,因为您已经将其定义为一次已同步,因此只有一个线程可以访问它,但是我认为,如果reaDall方法将不同步,那么同时两个线程可以调用这两个方法,即一个可以调用remove,而一个可以读取所有方法,在这种情况下,脏数据可能存在于您的计算机中对象。所以最好使用synchronized方法

I think that you should use synchonized blocks for putting new keys. All in all simply use ConcurrentHashMap as map implementation in concurrent environement.

public Map<Integer, MyResource> getResources(){
     return resources;
}


public Map<Integer, MyResource> getResources(){
   synchronized(resources){
       return resources;
   }
}

both the ways are not immune of issues. As you are sending the original Map to your consumer so they can change it which will impact your class invariant. You use defensive copy , or use immutable map ie Collections.unmodifiableMap .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM