public abstract class LazyLoadingMapping { private Map store; private Set toFetch; private Thread dataFetcher; public LazyLoadingMap() { dataFetcher = new Thread(new DataFetcher(1000)); } /** * Actually fetch a single item. */ protected abstract DataItem doFetch(DataKey id); /** * Public API for resolving an id to data. */ public DataType fetch(DataKey id) { // not convinced that the synchronization here is perfect synchronized(store) { DataType dt = store.get(id); if(dt == null) { synchronized(toFetch) { dt = doFetch(id); toFetch.remove(id); } } return dt; } } /** * Public API for indicating that we may wish to resolve an ID to data soon. */ public void interestedIn(DataKey id) { synchronized(toFetch) { toFetch.add(id); } } private class DataFetcher extends Runnable { private final long sleepTime; DataFetcher(long sleepTime) { this.sleepTime = sleepTime; } public void run() { while(true) { synchronized(toFetch) { for(DataKey dk: toFetch) { DataType dt = doFetch(dk); synchronzied(store) { store.put(dk, dt); } } } synchronized(this) { // todo: add exception handlers sleep(sleepTime); } } } } }