package com.charles.utils;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class CharlesCache {
private Map<String, Object> data = new HashMap<String, Object>();
private ReentrantReadWriteLock rwlock = new ReentrantReadWriteLock();
public static void main(String[] args) {
CharlesCache cache = new CharlesCache();
int i=0;
//define 3 threads to load data;
final int NUM= 3;
while(i++ < NUM){
new Thread(new Runnable(){
@Override
public void run() {
while(true){
String key = Thread.currentThread().getName();
Object value = cache.getCachedData(key);
System.out.println(value+", "+key);
try{
Thread.sleep(2000);
}catch(InterruptedException e){
}
}
}
}).start();
}
}
public Object getCachedData(String key) {
rwlock.readLock().lock();
Object value = null;
try {
value = data.get(key);
if (null != value) {
return value;
} else {
/*
* Here, no data to get, Must release read lock before acquiring
* write lock to load data from somewhere like database.
*/
rwlock.readLock().unlock();
rwlock.writeLock().lock();
/*
* Recheck state because another thread might have acquired
* write lock and changed state before we did.
*/
try {
if (null == value) {
value = loadDataFromDB(key);
data.put(key, value);// put value into cache
}
// Downgrade by acquiring read lock before releasing write lock
rwlock.readLock().lock();
} finally {
rwlock.writeLock().unlock(); // Unlock write, still hold
// read
}
}
} finally {
rwlock.readLock().unlock();
}
return value;
}
private Object loadDataFromDB(String key) {
Object value = null;
// need to be implemented...
System.out.println(Thread.currentThread().getName()+" acquiring data..");
value = "Hello";
return value;
}
}