6

I am writing a web-service that heavily relies on a single large Map that is completely updated once every hour. The rest of the time many threads concurrently read the table.

My question is: What is the most efficient construct to realize such a Map?

The Map can be rather larger (100 - 500 MB). There is only read access except once an hour where the whole map is replaced.

I was thinking about just using a Java HashMap and maybe using reflection to set the field final between the updates if this improves performance, but I have no clue how to make the JVM optimize for many concurrent reads.

xgb84j
  • 519
  • 2
  • 8
  • 19
  • 2
    The access could be managed from outside, via a `ReadWriteLock`. Apart from that, is your intention to make it more efficient than a "normal" HashMap? – Marco13 Feb 06 '14 at 23:25
  • 4
    Do you have some evidence that the normal HashMap is not sufficient? – Jakub Kotowski Feb 06 '14 at 23:26
  • The thing I am most afraid is that each thread has its own copy. Also I read that ConcurrentHashMap has only advantages for concurrent writing. – xgb84j Feb 06 '14 at 23:32

4 Answers4

18

Since the map isn't updated while being used, use a HashMap, which gives excellent O(1) lookup performance (at the sacrifice of thread safety).

When it's time to refresh, build a new map and swap references.

Consider using an AtomicReference to make the swap thread safe:

private final AtomicReference<Map<K, V>> mapRef = new AtomicReference<>();

To use:

mapRef.get().get(key);

To initialize or swap in a new map:

Map<K, V> newMap = new HashMap<>();
// populate map
mapRef.set(newMap); // all threads will see this change
Bohemian
  • 412,405
  • 93
  • 575
  • 722
  • Thank you this is also something I considered! But could you explain what you mean about using an "AtomicReference"? – xgb84j Feb 06 '14 at 23:31
3

Go for ConcurrentHashMap. It allows Concurrent read access without compromising on performance.

Keyur
  • 31
  • 1
2

In your scenario, until you have proved that Java's standard HashMap is not fast enough, I think you might need to worry about garbage collection if stop the world here and there might pose a problem.

You can avoid the problem by always reusing the HashMap (not creating a new one each time) and preallocating all the objects that you store in the map and reusing them too.

Apart from that, you can make the replacements faster by using two HashMaps as @Bohemian suggests in his answer.

Jakub Kotowski
  • 7,411
  • 29
  • 38
-1

Use this.

public class Model {
  private Map<?, ?> values;
  private ReadWriteLock lock = new ReentrantReadWriteLock();

  public ? getValue(? key) {
    lock.readLock().lock();
    ? rv = values.get(key);
    lock.readLock().unlock();
    return rv;
  }

  public void update(Map<?, ?> values) {
    lock.writeLock().lock();
    rv = values;
    //OR rv.putAll(values)
    lock.writeLock().unlock();
  }
}
gvaish
  • 9,374
  • 3
  • 38
  • 43