simple LRU standalone cache

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * A simple LRU cache
 * 
 * @author dennyliu
 * 
 * @param <K>
 * @param <V>
 */
public class LRUCache<K extends Serializable, V> {

    /**
     * The map where the keys and values are stored in.
     */
    private Map<K, Node> map = Collections.synchronizedMap(new HashMap<K, Node>());

    private Node start = new Node(); // head node
    private Node end = new Node(); // the last node
    private int maxSize;
    private final Object lockObject = new Object();

    /**
     * a simple linked node class
     * 
     */
    protected static class Node {
        public Node(Serializable key, Object value, long expires) {
            this.key = key;
            this.value = value;
            this.expires = expires;
        }


        public Node() {
        }

        public Serializable key;
        public Object value;
        public long expires;
        public Node previous;
        public Node next;
    }


    protected void removeNode(Node node) {
        synchronized (lockObject) {
            node.previous.next = node.next;
            node.next.previous = node.previous;
        }
    }


    protected void insertHead(Node node) {
        synchronized (lockObject) {
            node.previous = start;
            node.next = start.next;
            start.next.previous = node;
            start.next = node;
        }
    }


    protected void moveToHead(Node node) {
        synchronized (lockObject) {
            node.previous.next = node.next;
            node.next.previous = node.previous;
            node.previous = start;
            node.next = start.next;
            start.next.previous = node;
            start.next = node;
        }
    }


    /**
     * Constractor for LRUCache
     * 
     * @param maxSize
     *            How many objects can the cache hold
     */
    public LRUCache(int maxSize) {
        this.maxSize = maxSize;
        this.start.next = end;
        this.start.previous = null;
        this.end.previous = start;
        this.end.next = null;
    }

    public static class Pair<K, V> {
        private K key;
        private V value;


        public Pair(K key, V value) {
            this.key = key;
            this.value = value;
        }


        public K getKey() {
            return key;
        }


        public void setKey(K key) {
            this.key = key;
        }


        public V getValue() {
            return value;
        }


        public void setValue(V value) {
            this.value = value;
        }


        @Override
        public String toString() {
            StringBuilder builder = new StringBuilder();
            builder.append("Pair [key=");
            builder.append(key);
            builder.append(", value=");
            builder.append(value);
            builder.append("]");
            return builder.toString();
        }

    }


    public List<Pair<Serializable, Object>> getAll() {
        List<Pair<Serializable, Object>> list = new ArrayList<Pair<Serializable, Object>>(maxSize);
        synchronized (lockObject) {
            Node currentNode = start.next;
            while (currentNode != end) {
                list.add(new Pair<Serializable, Object>(currentNode.key, currentNode.value));
                currentNode = currentNode.next;
            }
        }
        return list;
    }


    @SuppressWarnings("unchecked")
    public V get(K key) {
        Node currentNode = map.get(key);

        if (currentNode == null) {
            return null;
        }

        if (System.currentTimeMillis() > currentNode.expires) {
            map.remove(currentNode.key);
            removeNode(currentNode);
            return null;
        }

        if (currentNode != start.next) {
            moveToHead(currentNode);
        }

        return (V) currentNode.value;
    }


    public void put(K key, V obj) {
        put(key, obj, -1);
    }


    public void put(K key, V value, long validTime) {
        Node currentNode = map.get(key);

        if (currentNode != null) {
            currentNode.value = value;
            if (validTime > 0) {
                currentNode.expires = System.currentTimeMillis() + validTime;
            }
            else {
                currentNode.expires = Long.MAX_VALUE;
            }
            moveToHead(currentNode);
            return;
        }

        if (map.size() >= maxSize) {
            // remove the last node
            currentNode = end.previous;
            map.remove(currentNode.key);
            removeNode(currentNode);
        }

        long expires = 0;

        if (validTime > 0) {
            expires = System.currentTimeMillis() + validTime;
        }
        else {
            expires = Long.MAX_VALUE;
        }

        Node node = new Node(key, value, expires);
        insertHead(node);
        map.put(key, node);
    }


    public void remove(K key) {
        Node cur = map.get(key);
        if (cur == null) {
            return;
        }
        map.remove(key);
        removeNode(cur);
    }


    public int size() {
        return map.size();
    }


    public static void main(String[] args) {
        LRUCache<String, String> cache = new LRUCache<String, String>(3);
        cache.put("111", "111");
        cache.put("222", "222");
        cache.put("333", "333");
        System.out.println(cache.getAll());
        cache.get("111");
        System.out.println(cache.getAll());
        cache.put("444", "444");
        System.out.println(cache.getAll());
        cache.put("555", "555");
        System.out.println(cache.getAll());
    }
}

你可能感兴趣的:(simple)