Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use ReadWriteLock?

Tags:

java

caching

map

I'm the following situation.

At web application startup I need to load a Map which is thereafter used by multiple incoming threads. That is, requests comes in and the Map is used to find out whether it contains a particular key and if so the value (the object) is retrieved and associated to another object.

Now, at times the content of the Map changes. I don't want to restart my application to reload the new situation. Instead I want to do this dynamically.

However, at the time the Map is re-loading (removing all items and replacing them with the new ones), concurrent read requests on that Map still arrive.

What should I do to prevent all read threads from accessing that Map while it's being reloaded ? How can I do this in the most performant way, because I only need this when the Map is reloading which will only occur sporadically (each every x weeks) ?

If the above is not an option (blocking) how can I make sure that while reloading my read request won't suffer from unexpected exceptions (because a key is no longer there, or a value is no longer present or being reloaded) ?

I was given the advice that a ReadWriteLock might help me out. Can you someone provide me an example on how I should use this ReadWriteLock with my readers and my writer ?

Thanks,
E

like image 372
EdwinDhondt Avatar asked Oct 29 '09 12:10

EdwinDhondt


2 Answers

I suggest to handle this as follow:

  1. Have your map accessible at a central place (could be a Spring singleton, a static ...).
  2. When starting to reload, let the instance as is, work in a different Map instance.
  3. When that new map is filled, replace the old map with this new one (that's an atomic operation).

Sample code:

    static volatile Map<U, V> map = ....;

    // **************************

    Map<U, V> tempMap = new ...;
    load(tempMap);
    map = tempMap;

Concurrency effects :

  • volatile helps with visibility of the variable to other threads.
  • While reloading the map, all other threads see the old value undisturbed, so they suffer no penalty whatsoever.
  • Any thread that retrieves the map the instant before it is changed will work with the old values.
    • It can ask several gets to the same old map instance, which is great for data consistency (not loading the first value from the older map, and others from the newer).
    • It will finish processing its request with the old map, but the next request will ask the map again, and will receive the newer values.
like image 144
KLE Avatar answered Oct 01 '22 20:10

KLE


If the client threads do not modify the map, i.e. the contents of the map is solely dependent on the source from where it is loaded, you can simply load a new map and replace the reference to the map your client threads are using once the new map is loaded.

Other then using twice the memory for a short time, no performance penalty is incurred.

In case the map uses too much memory to have 2 of them, you can use the same tactic per object in the map; iterate over the map, construct a new mapped-to object and replace the original mapping once the object is loaded.

like image 41
rsp Avatar answered Oct 01 '22 21:10

rsp