Java--緩存熱點數據,最近最少使用算法


1、最近最少使用算法LRU (Least recently used,最近最少使用)

【實現】:最常見的是使用一個鏈表保存緩存數據

1、新數據插入到鏈表頭部;

2、每當緩存命中(即緩存數據被訪問),將數據移動到鏈表頭部;

3、當鏈表滿的時候將鏈表尾部的數據丟棄;

 

【代價】

命中時需要遍歷鏈表,找到命中的數據塊索引,然后需要將數據移到頭部。

 

【改變】

基於以上代價,我們將維護的鏈表改為一個雙向鏈表(即每個節點都有個prev和next),另外需要再多維護一個map,將緩存對象的引用放入map中;

1、新數據插入鏈表頭部,並且放入map中

2、每當需要使用緩存時,首先通過key到map中查找,命中緩存后將數據移動到鏈表頭部(這個移動就非常好移動了,只需要把該節點的prev節點的next屬性賦值為該節點的next節點,同時把該節點的next節點的prev屬性賦值為該節點的prev節點,並且將該節點放入鏈表頭部就可以了)。

3、當鏈表滿的時候將鏈表尾部的數據丟棄,並且刪除map中對應的數據。

 

【結果】

基於以上改變的LRU算法,完全去除了命中緩存需要遍歷鏈表這個缺點,性能得到了大的提升。

 

2、使用redis緩存數據,保證熱點數據的緩存用法與原理

說一點:只要限制了redis占用的內存,redis會根據自身數據淘汰策略,加載熱數據到內存。

【實現】:

通過redis本身的設置過期時間來實現緩存熱點數據

1、緩存每命中一次,就重新給該數據設置過期時間

2、那么經常命中的緩存始終不會過期,不會被刪除,而非熱點數據過期時間一到那么就會被刪除掉,保證了redis中始終存在的是熱點數據。

 

【原理】

1、原理其實就是Java中延時阻塞隊列DelayQueue的原理

2、當對redis中緩存數據設置過期時間,相當於將緩存數據放入redis中維護的延時阻塞隊列DelayQueue。

3、DelayQueue會對放入的緩存數據根據過期時間進行排序,時間短的在前面,時間長的在隊列后面。

4、會使用一個或者多個線程循環查詢DelayQueue,一旦能從DelayQueue獲取元素了就說明該緩存數據到期了,就可以取出來並且刪除掉了。

5、當有多個線程都同時查詢DelayQueue的時候,只有一個線程能夠爭取到頭元素,其它線程將被阻塞。當頭元素被取走以后,會喚醒所有阻塞線程,線程競爭頭元素,競爭到頭元素的線程會查詢頭元素的剩余delay時間,並且標記頭元素已經被該線程占有,再根據delay時間wait自己,最后獲取頭元素后喚醒其它阻塞線程。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM