/* * Copyright 2013 Simon Thiel * * This file is part of SitJar. * * SitJar is free software: you can redistribute it and/or modify * it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * SitJar is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with SitJar. If not, see <http://www.gnu.org/licenses/lgpl.txt>. */ /** * @author Simon Thiel <simon.thiel at gmx.de> * @version $Revision: $ */ package sit.sstl; import java.util.Comparator; import java.util.HashMap; import java.util.Map; import java.util.TreeMap; import java.util.logging.Level; import java.util.logging.Logger; /** * * TODO: check potentially more efficient solution using LinkedHashMap: * public class LRUCache { public static final int MAX_ENTRIES = 50; private Map cache; public LRUCache(){ cache = new LinkedHashMap(MAX_ENTRIES+1, 0.70f, true){ @Override public boolean removeEldestEntry(Map.Entry eldest) { return size() > MAX_ENTRIES; } }; } * * * * @author Simon Thiel <simon.thiel at gmx.de> */ public class LRUCache<K, V> { private HashMap<K, V> map; private TreeMap<Long, K> timeMap; private int maxEntries; private long hashCount = 0; public LRUCache(int maxEntries) { this.maxEntries = maxEntries; map = new HashMap((int)(0.5*maxEntries)); timeMap = new TreeMap(new Comparator() { public int compare(Object o1, Object o2) { if (o1 == o2){ return 0; } return (int) ((Long) o1 - (Long) o2); } }); } private synchronized void trimIfRequired() { if (map.size() > maxEntries && !map.isEmpty()) { //trim is required K key = timeMap.remove(timeMap.firstKey()); map.remove(key); } } private synchronized Map.Entry<Long,K> getTimeMapSet(K key){ for (Map.Entry<Long,K> entry :timeMap.entrySet()){ if (entry.getValue().equals(key)){ return entry; } } return null; } public synchronized void reset(){ hashCount = 0; map.clear(); timeMap.clear(); } private synchronized void updateTimeMap(K key){ if (map.containsKey(key)){ //key was already in the list //remove old entry timeMap.remove(getTimeMapSet(key).getKey()); } hashCount++; if (hashCount<0){ Logger.getLogger(getClass().getName()).log(Level.SEVERE, "HashCount overflow - resetting hash"); reset(); } timeMap.put(hashCount, key); } public synchronized void put(K key, V value) { updateTimeMap(key); map.put(key, value); trimIfRequired(); } public synchronized V get(K key) { updateTimeMap(key); return map.get(key); } public synchronized boolean containsKey(K key) { return map.containsKey(key); } public static void main(String[] args) { LRUCache<Integer, String> myCache = new LRUCache(4); myCache.put(1,"a"); myCache.put(2,"b"); myCache.put(3,"c"); myCache.get(1); myCache.put(4,"d"); myCache.put(5,"e"); myCache.put(6,"f"); for (int i=0; i<7;i++){ System.out.println(i+" --> "+myCache.get(i)); } } }