简体   繁体   中英

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;
    }
}

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.

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();
}

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