Abe
Abe

Reputation: 9031

reload multiple caches which have concurrent readers simultaneously

I have reference data stored in a class using multiple hash maps

Map map1;
Map map2;
Map map3;

They are accessed concurrently by multiple readers. I want to re-initialize them all at the same time. If it were a single map, i could just do

public void reload(){
    map1 = createNewMapWithLatestData();
}

Since the existing readers have the old reference and the new readers get the new reference it works fine. But since I have multiple maps it is possible that new readers could get latest version of say map1 and map2 but an older version of map3, since the replace operation is not atomic.

Ok, so I need to lock this down, which brings me to my question. Other than locking down everything using a synchronized, what is an elegant way to do this?

I only need a lock when the reload is actually happening, not at other times. I looked at java locks(Read write), Conditions, CyclicBarriers, Countdownlatches and so on, but not sure what is the right approach for this.

Upvotes: 2

Views: 110

Answers (3)

alex
alex

Reputation: 115

Since you want to invalidate all the caches at the same time, you can

  • block everything with a syncrhonized as you said
  • use a flag to set them "invalid" and forbid the access of the reader till all of them are reloaded. If the cache reload is expensive, you could set a flag for every cache to signal which cache is invalid. It really depends on your application

The most elegant option would be to use something ready like spring cache (if you are using spring), it also manages distributed caches

Upvotes: 1

Gavriel
Gavriel

Reputation: 19237

If you create new maps, then the readers will need to have a way to get the new map's reference anyway. So instead of referencing directly mapX, keep a reference to an object that holds all the maps. That can be replaced atomicly as you just assign the new Object's reference, like you did in your example. Instead of using map1, you'll have holder.map1 in every place.

class Holder {
    Map map1;
    Map map2;
}

class Reader {
    Holder holder;
    void read() {
        writer.getHolder().map1.get("x");
    }
}

class Writer {
    Holder holder;
    Holder getHolder() {
        return holder;
    }
    void reload() {
        Holder newHolder = new Holder();
        newHolder.map1 = createNewMap1WithLatestData();
        newHolder.map2 = createNewMap2WithLatestData();
        holder = newHolder; // this is atomic
    }
}

Upvotes: 1

Andremoniy
Andremoniy

Reputation: 34900

You provide a very little amount of code, so the answer will be similar. Yes, you need ReadWriteLock. Please read tutorials about it. In brief, you always allow reading maps (read lock). But when you want to synchronise their initialization, you "turn on" write lock, this locks all lockable blocks and do not allow reading or writing to maps while you are initializating them.

Upvotes: 0

Related Questions