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