隨着互聯網的高速發展,市面上也出現了愈來愈多的網站和app。咱們判斷一個軟件是否好用,用戶體驗就是一個重要的衡量標準。好比說咱們常常用的微信,打開一個頁面要十幾秒,發個語音要幾分鐘對方纔能收到。相信這樣的軟件你們確定是都不肯意用的。軟件要作到用戶體驗好,響應速度快,緩存就是必不可少的一個神器。緩存又分進程內緩存和分佈式緩存兩種:分佈式緩存如redis、memcached等,還有本地(進程內)緩存如ehcache、GuavaCache、Caffeine等。提及Guava Cache,不少人都不會陌生,它是Google Guava工具包中的一個很是方便易用的本地化緩存實現,基於LRU算法實現,支持多種緩存過時策略。因爲Guava的大量使用,Guava Cache也獲得了大量的應用。可是,Guava Cache的性能必定是最好的嗎?也許,曾經它的性能是很是不錯的。正所謂長江後浪推前浪,前浪被拍在沙灘上。咱們就來介紹一個比Guava Cache性能更高的緩存框架:Caffeine。html
Tips: Spring5(SpringBoot2)開始用Caffeine取代guava.詳見官方信息SPR-13797
https://jira.spring.io/browse...
如下測試都是基於jmh測試的,官網地址
測試爲何要基於jmh測試,能夠參考知乎上R回答java
在HotSpot VM上跑microbenchmark切記不要在main()裏跑循環計時就完事。這是典型錯誤。重要的事情重複三遍:請用JMH,請用JMH,請用JMH。除非很是瞭解HotSpot的實現細節,在main裏這樣跑循環計時獲得的結果其實對通常程序員來講根本沒有任何意義,由於沒法解釋。
能夠從數據看出來Caffeine的性能都比Guava要好。而後Caffeine的API的操做功能和Guava是基本保持一致的,而且 Caffeine爲了兼容以前是Guava的用戶,作了一個Guava的Adapter給你們使用也是十分的貼心。git
<!-- https://mvnrepository.com/artifact/com.github.ben-manes.caffeine/caffeine --> <dependency> <groupId>com.github.ben-manes.caffeine</groupId> <artifactId>caffeine</artifactId> <version>2.8.2</version> </dependency>
Cache<String, Object> cache = Caffeine.newBuilder() .initialCapacity(100)//初始大小 .maximumSize(200)//最大數量 .expireAfterWrite(3, TimeUnit.SECONDS)//過時時間 .build();
建立參數介紹程序員
recordStats:開發統計功能github
注意:
expireAfterWrite和expireAfterAccess同時存在時,以expireAfterWrite爲準。maximumSize和maximumWeight不能夠同時使用。redis
Caffeine 爲咱們提供了手動、同步和異步這幾種填充策略。
下面咱們來演示下手動填充策略吧,其餘幾種若是你們感興趣的能夠去官網瞭解下算法
Cache<String, String> cache = Caffeine.newBuilder() .build(); cache.put("java金融", "java金融"); System.out.println(cache.getIfPresent("java金融"));
public static void main(String[] args) { Cache<String, String> cache = Caffeine.newBuilder() .build(); // 1.若是緩存中能查到,則直接返回 // 2.若是查不到,則從咱們自定義的getValue方法獲取數據,並加入到緩存中 String val = cache.get("java金融", k -> getValue(k)); System.out.println(val); } /** * 緩存中找不到,則會進入這個方法。通常是從數據庫獲取內容 * @param k * @return */ private static String getValue(String k) { return k + ":value"; }
Caffeine 爲咱們提供了三種過時策略
,分別是基於大小(size-based)、基於時間(time-based)、基於引用(reference-based)spring
LoadingCache<String, String> cache = Caffeine.newBuilder() // 最大容量爲1 .maximumSize(1) .build(k->getValue(k)); cache.put("java金融1","java金融1"); cache.put("java金融2","java金融2"); cache.put("java金融3","java金融3"); cache.cleanUp(); System.out.println(cache.getIfPresent("java金融1")); System.out.println(cache.getIfPresent("java金融2")); System.out.println(cache.getIfPresent("java金融3"));
運行結果以下:淘汰了兩個只剩下一個。數據庫
null null java金融3
Caffeine提供了三種定時驅逐策略:緩存
LoadingCache<String, String> cache = Caffeine.newBuilder() // 最大容量爲1 .maximumSize(1) .expireAfterWrite(3, TimeUnit.SECONDS) .build(k->getValue(k)); cache.put("java金融","java金融"); Thread.sleep(1*1000); System.out.println(cache.getIfPresent("java金融")); Thread.sleep(1*1000); System.out.println(cache.getIfPresent("java金融")); Thread.sleep(1*1000); System.out.println(cache.getIfPresent("java金融"));
運行結果第三秒的時候取值爲空。
java金融 java金融 null
LoadingCache<String, String> cache = Caffeine.newBuilder() // 最大容量爲1 .maximumSize(1) .expireAfterAccess(3, TimeUnit.SECONDS) .build(k->getValue(k)); cache.put("java金融","java金融"); Thread.sleep(1*1000); System.out.println(cache.getIfPresent("java金融")); Thread.sleep(1*1000); System.out.println(cache.getIfPresent("java金融")); Thread.sleep(1*1000); System.out.println(cache.getIfPresent("java金融")); Thread.sleep(3001); System.out.println(cache.getIfPresent("java金融"));
運行結果:讀和寫都沒有的狀況下,3秒後才過時,而後就輸出了null。
java金融 java金融 java金融 null
LoadingCache<String, String> cache = Caffeine.newBuilder() // 最大容量爲1 .maximumSize(1) .removalListener((key, value, cause) -> System.out.println("key:" + key + ",value:" + value + ",刪除緣由:" + cause)) .expireAfter(new Expiry<String, String>() { @Override public long expireAfterCreate(@NonNull String key, @NonNull String value, long currentTime) { return currentTime; } @Override public long expireAfterUpdate(@NonNull String key, @NonNull String value, long currentTime, @NonNegative long currentDuration) { return currentTime; } @Override public long expireAfterRead(@NonNull String key, @NonNull String value, long currentTime, @NonNegative long currentDuration) { return currentTime; } }) .build(k -> getValue(k));
本文只是對Caffeine的一個簡單使用的介紹,它還有不少不錯的東西,好比緩存監控、事件監聽、W-TinyLFU算法(高命中率、低內存佔用)感興趣的同窗能夠去官網查看。
https://www.itcodemonkey.com/...
https://juejin.im/post/5dede1...
https://www.cnblogs.com/Crank...
https://blog.csdn.net/hy24512...
https://github.com/ben-manes/...