Simple java cache implementation (LRU, LFU, FIFO)

The cache algorithm is also called the elimination algorithm, which is mainly used to clear the cache when the JVM space is insufficient. So if we want to clean up, which cache should we clean up first? According to normal people's thinking, of course, it is a cache that is unlikely to be used in the next period of time! According to this idea, we need to make certain judgments. There are usually three methods of judgment, namely LFU, LRU, and FIFO.

 

 

 

One more question, when will the cleanup take place? when?

 

I think it is generally possible to set a threshold to mark the minimum remaining space, which is to check the remaining space of the JVM when inserting. Or there is another method, which is to clean up regularly.

 

 

 

In addition, how to judge the pros and cons of the elimination algorithm?

 

Mainly is the size of the cache hit rate, followed by the difficulty of implementation.

 

1. LRU (Least Recently Used, least recently used)

 

The algorithm eliminates data based on the most recent access records of the data. The principle is that if the data has been accessed recently, the probability of being accessed in the future is relatively high. The most common implementation is to use a linked list to save the cached data. The detailed algorithm is as follows:

1. Insert new data into the head of the linked list;

2. Whenever the cache data hits, move the data to the head of the linked list;

3. When the linked list is full, discard the data at the end of the linked list.

 

 

 

My understanding of the LRU algorithm is that the queue is actually sorted according to the time of access. The recent access is at the head of the queue, and the long-term unvisited is at the end of the queue. Each time it is emptied, the data at the end of the queue is deleted. This method is especially good when using hotspot data.

 

[java] view plain copy

<pre name="code" class="java">/** 

 * project name: 

 * File description: Create a cache manager Liu Chenxi 

 * main feature: 

 * Version number: 1.0 

 * Creation time: 2013-12-3 

 **/  

package NBOffer;  

  

import games.MathTools;  

  

import java.util.ArrayList;  

import java.util.Collections;  

import java.util.Comparator;  

import java.util.Date;  

import java.util.Iterator;  

import java.util.List;  

import java.util.Map;  

import java.util.Set;  

import java.util.SortedMap;  

import java.util.TreeMap;  

  

public class CacheManager {  

  

    static SortedMap<String,Cache> cacheMap=new TreeMap<String,Cache>();  

    static final int MAX_CACHE_NUM=5;//Maximum five caches  

  

    private static class ValueComparator implements Comparator<Map.Entry<String,Cache>>  

    {  

        public int compare(Map.Entry<String,Cache> m,Map.Entry<String,Cache> n)  

        {  

            return (int) (n.getValue().tagDate.getTime()-m.getValue().tagDate.getTime());  

        }  

    }  

  

    public static Cache getCache(String id)  

    {  

        if(cacheMap.get(id)==null)  

        {  

            Object val=getFromDB(id);  

            cacheMap.put(id, new Cache(id,val));  

        }  

        Cache res=cacheMap.get(id);  

        try {  

            Thread.sleep(100);  

        } catch (InterruptedException e) {  

            e.printStackTrace ();  

        }  

        res.tagDate=new Date();  

        return cacheMap.get(id);  

    }  

  

    public static void putCache(Cache cache)  

    {  

        cacheMap. put(cache.id, cache);  

    }  

  

    public static Object getFromDB(String id)  

    {  

        System.out.println("Slowly read data corresponding to id="+id+" from memory...");     

        return new String("value"+id);  

    }  

  

    public static void refreshCaches()  

    {  

        System.out.println("Refresh cache...");  

  

        List<Map.Entry<String,Cache>> list=new ArrayList();  

        list.addAll(cacheMap.entrySet());  

        ValueComparator comparator=new ValueComparator();  

        Collections.sort(list,comparator);  

  

        for(Iterator<Map.Entry<String,Cache>> itea=list.iterator();itea.hasNext();)  

        {  

            System.out.println(itea.next());  

        }  

  

        for(int i=MAX_CACHE_NUM;i<list.size();i++)  

        {  

            String id=(String) list.get(i).getKey();  

            Object val=getFromDB(id);  

            cacheMap.put(id, new Cache(id,val));  

        }  

    }  

  

    public static void main(String[] args) throws InterruptedException {  

        Cache cache1=new Cache("1","value1");  

        Cache cache2=new Cache("2","value2");  

        Cache cache3=new Cache("3","value2");  

        Cache cache4=new Cache("4","value2");  

        Cache cache5=new Cache("5","value2");  

        Cache cache6=new Cache("6","value2");  

        Cache cache7=new Cache("7","value2");  

        CacheManager.putCache(cache1);  

        CacheManager.putCache(cache2);  

        CacheManager.putCache(cache3);  

        CacheManager.putCache(cache4);  

        CacheManager.putCache(cache5);  

        CacheManager.putCache(cache6);  

        CacheManager.putCache(cache7);  

        CacheManager.getCache("5");  

        CacheManager.getCache("6");  

        CacheManager.getCache("6");  

        refreshCaches();  

  

        Thread refreshTD=new Thread()  

        {  

            public void run()  

            {  

                while(true)  

                {  

                    refreshCaches();  

                    try {  

                        Thread.sleep(1000);//Refresh every second  

                    } catch (InterruptedException e) {  

                        e.printStackTrace ();  

                    }  

                }  

            }  

        };  

        //      refreshTD.start();  

    }  

}  

  

class Cache  

{  

    String id;//equivalent to primary key  

    Object val;  

    Date tagDate;//Mark date, when to use  

  

  

    public Cache(String id,Object val)  

    {  

        this.id=id;  

        this.val=val;  

        this.tagDate=new Date();  

    }  

  

    public void setValue(Object val)  

    {  

        this.val=val;  

        this.tagDate=new Date();  

    }  

  

    public void showInfo()  

    {  

        System.out.println("Cache's ID is: "+id+" Cache's value is: "+val);  

    }  

  

    public void setTagDate(Date dt)  

    {  

        this.tagDate=dt;  

    }  

  

}  

 

2. LFU (Least Frequently Used, Least Frequently Used)

The algorithm eliminates data according to the historical access frequency of the data. The principle is that if the data has been accessed more times in the past, the probability of being accessed in the future is relatively high. Each data block of an LFU has a reference count, all data blocks are sorted by reference count, and data blocks with the same reference count are sorted by time.

The specific algorithm is as follows:

1. The newly added data is inserted at the end of the queue (because the reference count is 1);

2. After the data in the queue is accessed, the reference count is increased and the queue is reordered;

3. When the data needs to be eliminated, delete the last data block of the sorted list;

 

 

My understanding of the LFU algorithm is that the queue is actually sorted according to the frequency of access. The higher the frequency of access, the higher the access is at the head of the queue, and the lower at the tail of the queue. Each time it is emptied, the data at the end of the queue is deleted. For occasional and periodic batch operations, the LRU hit rate will drop sharply, and the cache pollution will be serious. The efficiency of LFU is better than that of LRU, and it can avoid the problem of decreasing cache hit rate caused by periodic or sporadic operations. This method is particularly good. code show as below:

 

 

[java] view plain copy

/** 

 * project name: 

 * File description: Create a cache manager Liu Chenxi 

 * main feature: 

 * Version number: 1.0 

 * Creation time: 2013-12-3 

 **/  

package NBOffer;  

  

import games.MathTools;  

  

import java.util.ArrayList;  

import java.util.Collections;  

import java.util.Comparator;  

import java.util.Date;  

import java.util.Iterator;  

import java.util.List;  

import java.util.Map;  

import java.util.Set;  

import java.util.SortedMap;  

import java.util.TreeMap;  

  

public class CacheManager {  

  

    static SortedMap<String,Cache> cacheMap=new TreeMap<String,Cache>();  

    static final int MAX_CACHE_NUM=5;//Maximum five caches  

  

    private static class ValueComparator implements Comparator<Map.Entry<String,Cache>>  

    {  

        public int compare(Map.Entry<String,Cache> m,Map.Entry<String,Cache> n)  

        {  

            return n.getValue().usedcount-m.getValue().usedcount;  

        }  

    }  

  

    public static Cache getCache(String id)  

    {  

        if(cacheMap.get(id)==null)  

        {  

            Object val=getFromDB(id);  

            cacheMap.put(id, new Cache(id,val));  

        }  

        Cache res=cacheMap.get(id);  

        try {  

            Thread.sleep(100);  

        } catch (InterruptedException e) {  

            e.printStackTrace ();  

        }  

        res.addCount();  

        return cacheMap.get(id);  

    }  

  

    public static void putCache(Cache cache)  

    {  

        cacheMap. put(cache.id, cache);  

    }  

  

    public static Object getFromDB(String id)  

    {  

        System.out.println("Slowly read data corresponding to id="+id+" from memory...");     

        return new String("value"+id);  

    }  

  

    public static void refreshCaches()  

    {  

        System.out.println("Refresh cache...");  

  

        List<Map.Entry<String,Cache>> list=new ArrayList();  

        list.addAll(cacheMap.entrySet());  

        ValueComparator comparator=new ValueComparator();  

        Collections.sort(list,comparator);  

  

        for(int i=MAX_CACHE_NUM;i<list.size();i++)  

        {  

            String id=(String) list.get(i).getKey();  

            Object val=getFromDB(id);  

            cacheMap.put(id, new Cache(id,val));  

        }  

    }  

  

    public static void main(String[] args) throws InterruptedException {  

        Cache cache1=new Cache("1","value1");  

        Cache cache2=new Cache("2","value2");  

        Cache cache3=new Cache("3","value2");  

        Cache cache4=new Cache("4","value2");  

        Cache cache5=new Cache("5","value2");  

        Cache cache6=new Cache("6","value2");  

        Cache cache7=new Cache("7","value2");  

        CacheManager.putCache(cache1);  

        CacheManager.putCache(cache2);  

        CacheManager.putCache(cache3);  

        CacheManager.putCache(cache4);  

        CacheManager.putCache(cache5);  

        CacheManager.putCache(cache6);  

        CacheManager.putCache(cache7);  

        CacheManager.getCache("1");  

        CacheManager.getCache("1");  

        CacheManager.getCache("2");  

        CacheManager.getCache("3");  

        CacheManager.getCache("3");  

        CacheManager.getCache("4");  

        CacheManager.getCache("4");  

        CacheManager.getCache("6");  

        CacheManager.getCache("5");  

        CacheManager.getCache("5");  

        CacheManager.getCache("6");  

        CacheManager.getCache("6");  

        refreshCaches();  

  

        Thread refreshTD=new Thread()  

        {  

            public void run()  

            {  

                while(true)  

                {  

                    refreshCaches();  

                    try {  

                        Thread.sleep(1000);//Refresh every second  

                    } catch (InterruptedException e) {  

                        e.printStackTrace ();  

                    }  

                }  

            }  

        };  

                refreshTD.start();  

    }  

}  

  

class Cache  

{  

  

    String id;//equivalent to primary key  

    Object val;  

    Date startdt;//Mark the new time  

    int usedcount=0;//Mark usage count  

      

      

    public Cache(String id,Object val)  

    {  

        this.id=id;  

        this.val=val;  

        this.startdt=new Date();  

        usedcount++;  

    }  

      

    public void setValue(Object val)  

    {  

        this.val=val;  

    }  

      

    public void addCount()  

    {  

        usedcount++;  

    }  

      

    public void showInfo()  

    {  

        System.out.println("Cache's ID is: "+id+" Cache's value is: "+val);  

    }  

      

    /** 

     * Often the newly created ones have the least chance of being accessed 

     * @param o 

     * @return 

     */  

    public int compareTo(Object o) {  

        if(o instanceof Cache)  

        {  

            Cache c=(Cache) o;  

            if(this.usedcount>c.usedcount)  

                return 1;  

            else  

                return -1;  

        }  

        return 0;  

    }  

  

}  

 

3. FIFO (First In First Out, first in first out)

The algorithm is based on the principle of first-in-first-out to eliminate data, and the implementation is the simplest one. The specific algorithm is as follows:

1. The newly accessed data is inserted into the tail of the FIFO queue, and the data moves sequentially in the FIFO queue;

2. Eliminate the data at the head of the FIFO queue;

Although the implementation of FIFO is very simple, the hit rate is very low, and this algorithm is rarely used in practice.

 

The implementation method can be similar to LRU, except that the time for sorting does not refer to the last use time, but the creation time, so I won't go into details here.

 

http://blog.csdn.net/u011680348/article/details/47656401

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326977725&siteId=291194637