
org.lionsoul.jcseg.server.util.LRUCache Maven / Gradle / Ivy
package org.lionsoul.jcseg.server.util;
import java.util.HashMap;
/**
* LRU cache based on HashMap
*
* @author dongyado
* */
public class LRUCache {
@SuppressWarnings("hiding")
private class Entry {
public E key;
public T value;
public Entry prev;
public Entry next;
public Entry(E _key, T _val, Entry _prev, Entry _next)
{
this.key = _key;
this.value = _val;
this.prev = _prev;
this.next = _next;
}
}
private int capacity = 32; // default capacity
private int removePercent = 10; // 10% of the end of the list element to be removed when list fulled
private int length = 0;
private HashMap> map = null;
private Entry head;
private Entry tail;
public LRUCache(int capacity)
{
this.capacity = capacity;
this.init();
}
public LRUCache(int capacity, int percentToRemove)
{
this.capacity = capacity;
this.removePercent = percentToRemove;
this.init();
}
private void init() {
this.head = new Entry( null, null, null, null);
this.tail = new Entry( null, null, this.head, null);
this.head.next = this.tail;
this.map = new HashMap>();
}
/**
* get a element from map with specified key
*
* @param key
* @return value
* */
public T get( E key )
{
Entry entry = null;
synchronized(this) {
entry = map.get(key);
if (map.get(key) == null)
return null;
entry.prev.next = entry.next;
entry.next.prev = entry.prev;
entry.prev = this.head;
entry.next = this.head.next;
this.head.next.prev = entry;
this.head.next = entry;
}
return entry.value;
}
/**
* set a element to list
*
* @param key
* @param value
* */
public void set(E key, T value)
{
Entry entry = new Entry(key, value, null, null);
synchronized(this) {
if (map.get(key) == null) {
if (this.length >= this.capacity)
this.removeLeastUsedElements();
entry.prev = this.head;
entry.next = this.head.next;
this.head.next.prev = entry;
this.head.next = entry;
this.length++;
map.put(key, entry);
} else {
entry = map.get(key);
entry.value = value;
entry.prev.next = entry.next;
entry.next.prev = entry.prev;
entry.prev = this.head;
entry.next = this.head.next;
this.head.next.prev = entry;
this.head.next = entry;
}
}
}
/**
* remove a element from list
*
* @param key
* */
public synchronized void remove(E key)
{
Entry entry = map.get(key);
this.tail.prev = entry.prev;
entry.prev.next = this.tail;
map.remove(entry.key);
this.length--;
}
// remove least used elements
public synchronized void removeLeastUsedElements()
{
int rows = this.removePercent / 100 * this.length;
rows = rows == 0 ? 1 : rows;
while(rows > 0 && this.length > 0) {
// remove the last element
Entry entry = this.tail.prev;
this.tail.prev = entry.prev;
entry.prev.next = this.tail;
map.remove(entry.key);
this.length--;
rows--;
}
}
/**
* return the length of list
*
* @return int
* */
public synchronized int getLength(){
return this.length;
}
/**
* print the list
*
* @NOTE for test
* */
public synchronized void printList(){
Entry entry = this.head.next;
System.out.println("\n|----- key list----|");
while( entry != this.tail)
{
System.out.println(" -> " + entry.key );
entry = entry.next;
}
System.out.println("|------- end --------|\n");
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy