简体   繁体   中英

What kind of the Map interface I should use?

I need to make the following class thread-safe:

//Shared among all threads
public class SharedCache {

    private Map<Object, Future<Collection<Integer>>> chachedFutures;
    {
        chachedFutures = new ConcurrentHashMap<>(); //not sure about that
    }

    public Future<Collection<Integer>> ensureFuture(Object value,
                                                     FutureFactory<Collection<Integer>> ff){
        if(chachedFutures.containsKey(value))
            return chachedFutures.get(value);
        Future<Collection<Integer>> ftr = ff.create();
        chachedFutures.put(value, ftr);
        return ftr;
    }

    public Future<Collection<Integer>> remove(Object value){
        return chachedFutures.remove(value);
    }

}

After reading the article about the ConcurrentHashMap class it's still difficult for me to make a right decision.

Firstly, I tended to make the methods ensureFuture and remove just synchronized . And it would work, but from the performance standpoint it was not very good because of mutually-exclusing.

I don't know the exact (even approximately) amount of threads having access to the Cache simultaneously and the size of the Cache. Taking into account that

resizing this or any other kind of hash table is a relatively slow operation

I didn't specify the initial size of the map. Also the concurrencyLevel parameter. Is it justified to use ConcurrentHashMap here or synchronized methods would be enough?

You have following methods:

     public Future<Collection<Integer>> ensureFuture(Object value,
                                                     FutureFactory<Collection<Integer>> ff){
        if(chachedFutures.containsKey(value))
            return chachedFutures.get(value);
        Future<Collection<Integer>> ftr = ff.create();
        chachedFutures.put(value, ftr);
        return ftr;
    }

    public Future<Collection<Integer>> remove(Object value){
        return chachedFutures.remove(value);
    }

There are some points to be noticed:

  1. Suppose method ensureFuture is not synchronized in that case it is possible that one thread invokes containsKey which returns true but before next line is executed another thread may remove the entry respective to that key. This can lead to race condition as it is check-then-act scenario. Check this as well.
  2. Also you are using chachedFutures.put(value, ftr) but IMO you should use chachedFutures.putIfAbsent(value, ftr) . For this method if the specified key is not already associated with a value (or is mapped to null) associates it with the given value and returns null, else returns the current value . Using this you can also avoid contains check.

Is it justified to use ConcurrentHashMap here or synchronized methods would be enough?

It depends as CHM needs more memory compared to HashMap due to lot of bookkeeping activities etc. Another alternative is to use Collections.synchronizedMap which will provide synchronization on a regular HashMap .

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