Java實現緩衝(LRU,FIFO)

來源:互聯網
上載者:User

標籤:form   容量   redis   編寫   擴容   串連   大於   解決   app   

吹吹牛逼,晒晒太陽。不如來寫點東西,哈哈哈哈哈。。。。今天來說說,如何用java實現緩衝,這個話題很多面試的也會被問到。今天就來說說。

1.為什麼要java實現緩衝的?

由於目前軟體或網頁的並發量增加很大,大量請求直接操作資料庫,會對資料造成很大的壓力。處理大量請求和連線時間會很長。而我們知道資料庫中70%的資料是不需要修改的,那就可以引入緩衝來進行讀取,減少資料庫的壓力。

常用的緩衝有Redis和memcached,但是有時候一些小情境就可以直接使用Java實現緩衝,就可以滿足這部分服務的需求。

緩衝主要有LRU和FIFO,LRU是Least Recently Used的縮寫,即最近最久未使用,FIFO就是先進先出,

下面就使用Java來實現這兩種緩衝

一。LRU緩衝的思想

固定緩衝大小,需要給緩衝分配一個固定的 大小

每次讀取緩衝都會改變緩衝的使用時間,將緩衝存在的時間重新重新整理。

需要在緩衝滿後,將最近,最久,未使用的緩衝刪除,再添加心得緩衝。

按照上面的思想我們可以使用LikedHashMap來實現LRU緩衝

當返回true的時候,就會remove其中最久的元素,可以通過重寫這個方法來控制緩衝元素的刪除,當緩衝滿了後,就可以通過返回true刪除最久未被使用的元素,達到LRU的要求。這樣就可以滿足上述第三點要求。

protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {    return false;}

由於LinkedHashMap是為自動擴容的,當table數組中元素大於Capacity * loadFactor的時候,就會自動進行兩倍擴容。但是為了使緩衝大小固定,就需要在初始化的時候傳入容量大小和負載因子。
為了使得到達設定緩衝大小不會進行自動擴容,需要將初始化的大小進行計算再傳入,可以將初始化大小設定為(緩衝大小 / loadFactor) + 1,這樣就可以在元素數目達到緩衝大小時,也不會進行擴容了。這樣就解決了上述第一點問題。


代碼實現
package com.huojg.test.Test;import java.util.LinkedHashMap;import java.util.Map;import java.util.Set;public class LRUCache<K, V> {    private final int MAX_CACHE_SIZE;    private final float DEFAULT_LOAD_FACTORY = 0.75f;    LinkedHashMap<K, V> map;    public LRUCache(int cacheSize) {        MAX_CACHE_SIZE = cacheSize;        int capacity = (int)Math.ceil(MAX_CACHE_SIZE / DEFAULT_LOAD_FACTORY) + 1;        /*         * 第三個參數設定為true,代表linkedlist按訪問順序排序,可作為LRU緩衝         * 第三個參數設定為false,代表按插入順序排序,可作為FIFO緩衝         */        map = new LinkedHashMap<K, V>(capacity, DEFAULT_LOAD_FACTORY, true) {            @Override            protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {                return size() > MAX_CACHE_SIZE;            }        };    }    public synchronized void put(K key, V value) {        map.put(key, value);    }    public synchronized V get(K key) {        return map.get(key);    }    public synchronized void remove(K key) {        map.remove(key);    }    public synchronized Set<Map.Entry<K, V>> getAll() {        return map.entrySet();    }    @Override    public String toString() {        StringBuilder stringBuilder = new StringBuilder();        for (Map.Entry<K, V> entry : map.entrySet()) {            stringBuilder.append(String.format("%s: %s  ", entry.getKey(), entry.getValue()));        }        return stringBuilder.toString();    }    public static void main(String[] args) {        LRUCache<Integer, Integer> lru1 = new LRUCache<>(5);        lru1.put(1, 1);        lru1.put(2, 2);        lru1.put(3, 3);        System.out.println(lru1);        lru1.get(1);        System.out.println(lru1);        lru1.put(4, 4);        lru1.put(5, 5);        lru1.put(6, 6);        System.out.println(lru1);    }}

結果輸出:

1: 1  2: 2  3: 3  2: 2  3: 3  1: 1  3: 3  1: 1  4: 4  5: 5  6: 6  

實現了LRU緩衝的思想

 

FIFO

FIFO就是先進先出,可以使用LinkedHashMap進行實現。
當第三個參數傳入為false或者是預設的時候,就可以實現按插入順序排序,就可以實現FIFO緩衝了。

實現代碼跟上述使用LinkedHashMap實現LRU的代碼基本一致,主要就是建構函式的傳值有些不同。

package com.huojg.test.Test;import java.util.LinkedHashMap;import java.util.Map;import java.util.Set;public class FIFOCache<K, V> {    private final int MAX_CACHE_SIZE;    private final float DEFAULT_LOAD_FACTORY = 0.75f;    LinkedHashMap<K, V> map;    public FIFOCache(int cacheSize) {        MAX_CACHE_SIZE = cacheSize;        int capacity = (int)Math.ceil(MAX_CACHE_SIZE / DEFAULT_LOAD_FACTORY) + 1;        /*         * 第三個參數設定為true,代表linkedlist按訪問順序排序,可作為LRU緩衝         * 第三個參數設定為false,代表按插入順序排序,可作為FIFO緩衝         */        map = new LinkedHashMap<K, V>(capacity, DEFAULT_LOAD_FACTORY, false) {            @Override            protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {                return size() > MAX_CACHE_SIZE;            }        };    }    public synchronized void put(K key, V value) {        map.put(key, value);    }    public synchronized V get(K key) {        return map.get(key);    }    public synchronized void remove(K key) {        map.remove(key);    }    public synchronized Set<Map.Entry<K, V>> getAll() {        return map.entrySet();    }    @Override    public String toString() {        StringBuilder stringBuilder = new StringBuilder();        for (Map.Entry<K, V> entry : map.entrySet()) {            stringBuilder.append(String.format("%s: %s  ", entry.getKey(), entry.getValue()));        }        return stringBuilder.toString();    }    public static void main(String[] args) {        FIFOCache<Integer, Integer> lru1 = new FIFOCache<>(5);        lru1.put(1, 1);        lru1.put(2, 2);        lru1.put(3, 3);        System.out.println(lru1);        lru1.get(1);        System.out.println(lru1);        lru1.put(4, 4);        lru1.put(5, 5);        lru1.put(6, 6);        System.out.println(lru1);    }}

結果輸出

1: 1  2: 2  3: 3  1: 1  2: 2  3: 3  2: 2  3: 3  4: 4  5: 5  6: 6  

以上就是使用Java實現這兩種緩衝的方式,從中可以看出,LinkedHashMap實現緩衝較為容易,因為底層函數對此已經有了支援,自己編寫鏈表實現LRU緩衝也是借鑒了LinkedHashMap中實現的思想。在Java中不只是這兩種資料結構可以實現緩衝,比如ConcurrentHashMap、WeakHashMap在某些情境下也是可以作為緩衝的,到底用哪一種資料結構主要是看情境再進行選擇,但是很多思想都是可以通用的。






Java實現緩衝(LRU,FIFO)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.