@Test public void testEvictsWhenAtCapacityMultiThreaded() throws InterruptedException { final int limit = 1000; final int threadNumber = Runtime.getRuntime().availableProcessors() * 2; final CountBasedBackEnd<String, Element> countBasedBackEnd = new CountBasedBackEnd<String, Element>(limit); final AtomicInteger counter = new AtomicInteger(0); final Runnable runnable = new Runnable() { @Override public void run() { int i; while ((i = counter.getAndIncrement()) < limit * threadNumber * 10) { final String key = Integer.toString(i); countBasedBackEnd.putIfAbsent(key, new Element(key, i)); } } }; Thread[] threads = new Thread[threadNumber]; for (int i = 0, threadsLength = threads.length; i < threadsLength; i++) { threads[i] = new Thread(runnable); threads[i].start(); } for (Thread thread : threads) { thread.join(); } assertThat("Grew to " + countBasedBackEnd.size(), countBasedBackEnd.size() <= limit, is(true)); int size = countBasedBackEnd.size(); for (String s : countBasedBackEnd.keySet()) { assertThat(countBasedBackEnd.remove(s), notNullValue()); size--; } assertThat(size, is(0)); }
@Override public V putIfAbsent(final K key, final V value) { final V v = super.putIfAbsent(key, value); if (v == null) { try { evictIfRequired(key, value); } catch (Throwable e) { LOG.warn("Caught throwable while evicting", e); } } return v; }
CountBasedBackEnd extends ConcurrentHashMap<K, V> implements HeapCacheBackEnd<K, V> { @Override public V putIfAbsent(final K key, final V value) { final V v = super.putIfAbsent(key, value); if (v == null) { try { evictIfRequired(key, value); } catch (Throwable e) { LOG.warn("Caught throwable while evicting", e); } } return v; } }
CountBasedBackEnd extends ConcurrentHashMap<K, V> implements HeapCacheBackEnd<K, V> { @Override public V putIfAbsent(final K key, final V value) { final V v = super.putIfAbsent(key, value); if (v == null) { try { evictIfRequired(key, value); } catch (Throwable e) { LOG.warn("Caught throwable while evicting", e); } } return v; } CountBasedBackEnd(final long maxEntriesLocalHeap);  CountBasedBackEnd(final long maxEntriesLocalHeap, final Policy policy); }
CountBasedBackEnd extends ConcurrentHashMap<K, V> implements HeapCacheBackEnd<K, V> { @Override public V putIfAbsent(final K key, final V value) { final V v = super.putIfAbsent(key, value); if (v == null) { try { evictIfRequired(key, value); } catch (Throwable e) { LOG.warn("Caught throwable while evicting", e); } } return v; } CountBasedBackEnd(final long maxEntriesLocalHeap);  CountBasedBackEnd(final long maxEntriesLocalHeap, final Policy policy); void setPolicy(final Policy policy); @Override V putIfAbsent(final K key, final V value); @Override void registerEvictionCallback(final EvictionCallback<K, V> callback); @Override void recalculateSize(final K key); void setMaxEntriesLocalHeap(final long maxEntriesLocalHeap); long getMaxEntriesLocalHeap(); }
CountBasedBackEnd extends ConcurrentHashMap<K, V> implements HeapCacheBackEnd<K, V> { @Override public V putIfAbsent(final K key, final V value) { final V v = super.putIfAbsent(key, value); if (v == null) { try { evictIfRequired(key, value); } catch (Throwable e) { LOG.warn("Caught throwable while evicting", e); } } return v; } CountBasedBackEnd(final long maxEntriesLocalHeap);  CountBasedBackEnd(final long maxEntriesLocalHeap, final Policy policy); void setPolicy(final Policy policy); @Override V putIfAbsent(final K key, final V value); @Override void registerEvictionCallback(final EvictionCallback<K, V> callback); @Override void recalculateSize(final K key); void setMaxEntriesLocalHeap(final long maxEntriesLocalHeap); long getMaxEntriesLocalHeap();  }