RonR
RonR

Reputation: 39

Thread-safe resetting of an object's reference

The someParameters hashmap is loaded from a .csv file every twenty minutes or so by one thread and set by the setParameters method.

It is very frequently read by multiple threads calling getParameters: to perform a lookup translation of one value into a corresponding value.

Is the code unsafe and/ or the "wrong" way to achieve this (particularly in terms of performance)? I know about ConcurrentHashMap but am trying to get a more fundamental understanding of concurrency, rather than using classes that are inherrently thread-safe.

One potential risk I see is that the object reference someParameters could be reset whilst another thread is reading the copy, so the other thread might not have the latest values (which wouldn't matter to me).

public class ConfigObject {
    private static HashMap<String, String> someParameters = new HashMap<String, String>();

    public HashMap<String, String> getParameters(){
        return new HashMap<String, String>(someParameters);
        //to some thread which will only ever iterate or get
    }

    public void setParameters(HashMap<String, String> newParameters){
        //could be called by any thread at any time
        someParameters = newParameters;
    }
}

Upvotes: 1

Views: 249

Answers (2)

kr.pradeep
kr.pradeep

Reputation: 115

There are two problems here

  1. Visibility problem, as someParameters after update might not be visible to other thread, to fix this mark someParameters as volatile.
  2. Other problem is performance one due to creating new HashMap in get method, to fix that use Utility method Collections.unmodifiableMap() this just wrap original map and disallowing put/remove method.

Upvotes: 2

Alex Salauyou
Alex Salauyou

Reputation: 14348

If I understand your problem correctly, you need to change/replace many parameters at once (atomically). Unfortunately, ConcurrentHashMap doesn't support atomic bulk inserts/updates.

To achieve this, you should use shared ReadWriteLock. Advantage comparing to Collections.synchronized... is that concurrent reads can be performed simultaneously: if readLock is acquired from some thread, readLock().lock() called from another thread will not block.

ReadWriteLock lock = new ReadWriteLock();

// on write:
lock.writeLock().lock();
try {
   // write/update operation, 
   // e. g. clear map and write new values
} finally {
   lock.writeLock().unlock();
}

// on read:
lock.readLock().lock();
try {
   // read operation
} finally {
   lock.readLock().unlock();
}

Upvotes: 1

Related Questions