package de.invesdwin.util.collections.loadingcache.internal; import java.util.Collection; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock; import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; import java.util.function.Function; import javax.annotation.concurrent.ThreadSafe; import de.invesdwin.util.collections.loadingcache.ILoadingCache; @ThreadSafe public abstract class AReadWriteLockLoadingCache<K, V> implements ILoadingCache<K, V> { private final Map<K, V> map; private final Function<K, V> loadValue; private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); private final WriteLock writeLock = lock.writeLock(); private final ReadLock readLock = lock.readLock(); public AReadWriteLockLoadingCache(final Function<K, V> loadValue, final Map<K, V> map) { this.loadValue = loadValue; this.map = map; } @Override public V get(final K key) { V v = internalGet(key); if (v == null) { writeLock.lock(); try { v = loadValue.apply(key); map.put(key, v); } finally { writeLock.unlock(); } } return v; } private V internalGet(final K key) { readLock.lock(); try { return map.get(key); } finally { readLock.unlock(); } } @Override public void clear() { writeLock.lock(); try { map.clear(); } finally { writeLock.unlock(); } } @Override public boolean containsKey(final K key) { readLock.lock(); try { return map.containsKey(key); } finally { readLock.unlock(); } } @Override public void remove(final K key) { writeLock.lock(); try { map.remove(key); } finally { writeLock.unlock(); } } @Override public void put(final K key, final V value) { writeLock.lock(); try { map.put(key, value); } finally { writeLock.unlock(); } } @Override public Set<Entry<K, V>> entrySet() { readLock.lock(); try { return map.entrySet(); } finally { readLock.unlock(); } } @Override public int size() { readLock.lock(); try { return map.size(); } finally { readLock.unlock(); } } @Override public Set<K> keySet() { readLock.lock(); try { return map.keySet(); } finally { readLock.unlock(); } } @Override public Collection<V> values() { readLock.lock(); try { return map.values(); } finally { readLock.unlock(); } } }