
時隔多日,小菜雞終於接到阿里的面試通知,屁顛屁顛的從上海趕到了杭州。

經過半個小時的廝殺:
自我介紹
hashMap和ConcurrentHashMap區別
jdk中鎖的實現原理
volatile的使用場景
threadLocal怎么實現?什么時候會用到?
面試官終於把考察點轉到了redis上面,這是小菜雞特意准備過的。

面試官:我看你簡歷提到xxx項目使用了redis
小弱雞:嗯,因為xxxx的性能問題,經過排查之后,發現性能瓶頸在數據庫上面,所以引入了redis
面試官:行,那你了解redis的過期策略嗎?
小弱雞:有了解過,因為redis是基於內存來進行高性能、高並發的讀寫操作的,既然是內存,那肯定有空間的限制,如果只有10g內存,一直往里面寫數據,那肯定不行,所以采用一些過期策略把不需要的數據刪除、或者是淘汰掉。
面試官:那都有哪些過期策略?
小弱雞:我了解的有 定期刪除、惰性刪除兩種
面試官:你先講講定期刪除怎么實現?
小弱雞好像有點興奮:所謂定期刪除,指的是 redis 默認是每隔 100ms 就隨機抽取一些設置了過期時間的 key,檢查其是否過期,如果過期就刪除。
面試官:為什么是隨機抽取?
小弱雞:假如在redis 里插入10w個key,並且都設置了過期時間,如果每次都檢查所有key,那cpu基本上都消耗在過期key的檢查上了,redis對外的性能也會大大降低,簡直就是一場災難。
面試官:隨機檢查會存在什么問題?
小弱雞:可能導致本已經過期的key沒有被掃描到,而繼續留在內存中,並占用空間,等待被刪除。
面試官:這種情況怎么解決?
小弱雞又興奮了:這時候就需要第二種過期策略了,惰性刪除,就是在獲取某個 key 的時候,redis 會檢查一下 ,如果這個 key 設置了過期時間,並且已經過期了,那么就直接刪除,返回空。
面試官面帶一絲笑意:嗯,那再考慮一種情況,如果大量的key沒有被掃描到,且已過期,也沒有被再次訪問,即沒有走惰性刪除,這些大量過期 key 堆積在內存里,導致 redis 內存塊耗盡了,這種情況下,怎么辦?
小菜雞想了會,抓了抓腦袋:redis內部提供了內存淘汰機制,應該有好幾種策略,但我只知道LRU算法。
面試官:嗯,那你手寫一個LRU算法?
小菜雞*花一緊,這不是給自己挖坑么!!!如果從頭開始寫一個完整的LRU算法,那會要了命,幸好小菜雞還記得 LinkedHashMap,可以基於 LinkedHashMap實現一個簡單版本的LRU算法。
class LRUCache<K, V> extends LinkedHashMap<K, V> {
private final int CACHE_SIZE;
* @param cacheSize 緩存大小
*/
// true 表示讓 linkedHashMap 按照訪問順序來進行排序,最近訪問的放在頭部,最老訪問的放在尾部。
public LRUCache(int cacheSize) {
super((int) Math.ceil(cacheSize / 0.75) + 1, 0.75f, true);
CACHE_SIZE = cacheSize;
}
@Override
// 當 map中的數據量大於指定的緩存個數的時候,就自動刪除最老的數據。
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return size() > CACHE_SIZE;
}
}
小菜雞寫完之后,輕輕舒了一口氣。

面試官看完點點頭,換了個方向繼續虐!
本號專注於后端技術、JVM問題排查和優化、Java面試題、個人成長和自我管理等主題,為讀者提供一線開發者的工作和成長經驗,期待你能在這里有所收獲。

