You can refresh the cache using a pool of worker threads reading from a shared BlockingQueue; when the user finalizes their edit you'll send a message to the queue with information on the kv pairs that need to be updated.
public class RefreshRequest<K> {
public final K key;
public RefreshRequest(K key) { this.key = key; }
}
public final BlockingQueue<RefreshRequest<?>> requestQueue = new ArrayBlockingQueue<>(200);
public final int concurrency = 4;
public final ExecutorService executor = Executors.newFixedThreadPool(4);
for(int i = 0; i < concurrency; i++) {
executor.execute(new Runnable() {
public void run() {
try {
while(true) {
RefreshRequest<?> request = requestQueue.take();
// refresh key
}
} catch(InterruptedException e) {
return; // maybe log the exception as well
}
}
};
}
The workers will consume requests to refresh cache keys; you'll need to put
new requests on the queue from the code that finalizes a change to the xml file. To terminate the workers call executor.shutdownNow()
which will break out of the while(true)
loops with an InterruptedException
As for how to stop reading from the cache when somebody starts writing to the xml, you can do this with an "optimistic" read. Assign a version number to each xml file, and increment this version when you write to the file. When you start a read, store the file's version in a local variable. When the read finishes, compare the local version to the file's current version - if they match then return the read value, if they don't match then repeat the read including updating the local variable to the now-current file version. If need be you can have an "invalid" version (e.g. "valid" versions start at 0 and are incremented on each write, while an "invalid" version is negative-1) - if the reader reads that the file is "invalid" then it pauses for e.g. 5 seconds and then tries again. So one algorithm might be
public Object read(K key) {
while(true) {
int version = versionCache.get(key);
if(version == -1) Thread.sleep(5000);
else {
Object returnVal = cache.get(key);
if(version == versionCache.get(key))
return returnVal;
}
}
}