java中的本地緩存GuavaCache使用方法和示例教程
在現(xiàn)代互聯(lián)網(wǎng)應(yīng)用中,高并發(fā)場景是每個(gè)開發(fā)者都可能遇到的挑戰(zhàn)。為了提高系統(tǒng)的響應(yīng)速度和吞吐量,緩存技術(shù)成為了一個(gè)不可或缺的部分。Google Guava庫提供了一個(gè)強(qiáng)大的本地緩存實(shí)現(xiàn)——GuavaCache
,它不僅簡單易用,而且性能優(yōu)秀,非常適合處理高并發(fā)場景。
GuavaCache簡介
GuavaCache是Google Guava庫中的一個(gè)組件,用于實(shí)現(xiàn)內(nèi)存中的緩存。它支持多種配置選項(xiàng),如設(shè)置緩存大小、過期策略等,并且提供了線程安全的操作方法,使得在多線程環(huán)境中使用更加方便。
主要特性
線程安全
GuavaCache的所有操作都是線程安全的,這使得它在高并發(fā)環(huán)境下能夠穩(wěn)定運(yùn)行,無需額外的同步控制。
自動(dòng)加載
可以通過LoadingCache
接口實(shí)現(xiàn)數(shù)據(jù)的自動(dòng)加載,當(dāng)緩存中沒有找到對應(yīng)的鍵時(shí),會(huì)自動(dòng)調(diào)用指定的方法來加載數(shù)據(jù)。
過期策略
支持基于時(shí)間的過期策略,包括創(chuàng)建后過期(expire after write)和訪問后過期(expire after access)。
內(nèi)存回收
GuavaCache可以根據(jù)內(nèi)存情況自動(dòng)回收不常用的條目,避免內(nèi)存溢出。
使用示例
基本使用
首先,需要添加Guava庫到項(xiàng)目中,如果使用Maven,可以在pom.xml
中添加如下依賴:
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>31.0.1-jre</version> </dependency>
接下來,創(chuàng)建一個(gè)簡單的緩存實(shí)例:
import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; public class GuavaCacheExample { public static void main(String[] args) throws ExecutionException { // 創(chuàng)建一個(gè)LoadingCache實(shí)例 LoadingCache<String, String> cache = CacheBuilder.newBuilder() .maximumSize(100) // 設(shè)置緩存的最大容量 .expireAfterWrite(10, TimeUnit.MINUTES) // 設(shè)置過期時(shí)間為10分鐘 .build(new CacheLoader<String, String>() { // 定義默認(rèn)的數(shù)據(jù)加載機(jī)制 @Override public String load(String key) throws Exception { return "value-" + key; } }); // 訪問緩存 String value = cache.get("key1"); System.out.println(value); // 輸出: value-key1 } }
異常處理
在實(shí)際應(yīng)用中,數(shù)據(jù)加載可能會(huì)拋出異常。GuavaCache允許你定義如何處理這些異常:
try { String value = cache.get("key2"); } catch (ExecutionException e) { // 處理異常 System.err.println("Failed to load value for key2: " + e.getCause()); }
手動(dòng)加載和刪除
除了自動(dòng)加載外,還可以手動(dòng)將數(shù)據(jù)放入緩存或從緩存中刪除數(shù)據(jù):
// 手動(dòng)加載 cache.put("key3", "value3"); // 手動(dòng)刪除 cache.invalidate("key3");
性能優(yōu)化
并發(fā)級別
通過設(shè)置concurrencyLevel
參數(shù)可以調(diào)整緩存的并發(fā)性能,這個(gè)值表示預(yù)計(jì)同時(shí)訪問緩存的線程數(shù)。通常情況下,默認(rèn)值已經(jīng)足夠好,但在特定場景下適當(dāng)調(diào)整可以提升性能。
軟引用與弱引用
對于內(nèi)存敏感的應(yīng)用,可以考慮使用軟引用或弱引用來存儲(chǔ)緩存項(xiàng),這樣當(dāng)系統(tǒng)內(nèi)存不足時(shí),JVM會(huì)自動(dòng)回收這些對象。
CacheBuilder.newBuilder() .softValues() // 使用軟引用 .weakKeys() // 使用弱引用 .build();
GuavaCache是一個(gè)強(qiáng)大而靈活的緩存工具,特別適合于需要高性能和低延遲的應(yīng)用。通過合理配置,可以有效應(yīng)對高并發(fā)場景下的各種挑戰(zhàn)。這篇文章介紹了GuavaCache的基本概念、主要特性和使用方法,以及一些性能優(yōu)化的技巧,適合對緩存技術(shù)感興趣的開發(fā)者閱讀。Guava Cache 是一個(gè)非常高效的本地緩存庫,特別適合處理高并發(fā)場景。下面是一個(gè)使用 Guava Cache 的示例代碼,假設(shè)我們有一個(gè)需要頻繁查詢用戶信息的應(yīng)用場景。
場景描述
假設(shè)我們有一個(gè)用戶服務(wù),需要頻繁地從數(shù)據(jù)庫中查詢用戶信息。為了減少數(shù)據(jù)庫的訪問壓力,我們可以使用 Guava Cache 來緩存用戶信息。
依賴引入
首先,確保你的項(xiàng)目中已經(jīng)引入了 Guava 庫。如果你使用的是 Maven,可以在 pom.xml
中添加以下依賴:
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>31.0.1-jre</version> </dependency>
示例代碼
import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; public class UserCacheService { // 創(chuàng)建一個(gè) Guava Cache 實(shí)例 private final Cache<String, User> userCache; public UserCacheService() { // 配置緩存 this.userCache = CacheBuilder.newBuilder() .maximumSize(1000) // 最大緩存條目數(shù) .expireAfterWrite(10, TimeUnit.MINUTES) // 緩存條目在寫入后 10 分鐘過期 .recordStats() // 記錄緩存統(tǒng)計(jì)信息 .build(); } // 獲取用戶信息 public User getUser(String userId) { try { return userCache.get(userId, () -> loadUserFromDatabase(userId)); } catch (ExecutionException e) { throw new RuntimeException("Failed to load user from cache", e); } } // 從數(shù)據(jù)庫加載用戶信息 private User loadUserFromDatabase(String userId) { // 模擬從數(shù)據(jù)庫加載用戶信息 System.out.println("Loading user " + userId + " from database"); return new User(userId, "User Name " + userId); } public static void main(String[] args) { UserCacheService service = new UserCacheService(); // 模擬高并發(fā)請求 for (int i = 0; i < 10; i++) { new Thread(() -> { User user = service.getUser("12345"); System.out.println("User: " + user); }).start(); } } } class User { private String id; private String name; public User(String id, String name) { this.id = id; this.name = name; } @Override public String toString() { return "User{id='" + id + "', name='" + name + "'}"; } }
代碼解釋
- 緩存配置:
maximumSize(1000)
:設(shè)置緩存的最大條目數(shù)為 1000。expireAfterWrite(10, TimeUnit.MINUTES)
:設(shè)置緩存條目在寫入后 10 分鐘過期。recordStats()
:記錄緩存的統(tǒng)計(jì)信息,方便監(jiān)控和調(diào)試。
- 獲取用戶信息:
getUser
方法通過userCache.get
方法從緩存中獲取用戶信息。如果緩存中沒有該用戶信息,則調(diào)用loadUserFromDatabase
方法從數(shù)據(jù)庫中加載用戶信息,并將其存入緩存。
- 從數(shù)據(jù)庫加載用戶信息:
loadUserFromDatabase
方法模擬從數(shù)據(jù)庫中加載用戶信息的過程。
- 模擬高并發(fā)請求:
- 在
main
方法中,創(chuàng)建多個(gè)線程模擬高并發(fā)請求,每個(gè)線程都嘗試獲取同一個(gè)用戶的用戶信息。由于緩存的存在,多次請求只會(huì)觸發(fā)一次數(shù)據(jù)庫查詢。
備注
1. 基本概念
- Cache:Guava Cache的主要接口,用于定義緩存的基本操作,如獲取、插入和刪除緩存項(xiàng)。
- LoadingCache:繼承自
Cache
,提供了一種自動(dòng)加載數(shù)據(jù)到緩存中的機(jī)制,當(dāng)緩存中沒有請求的數(shù)據(jù)時(shí),可以自動(dòng)從數(shù)據(jù)源加載。 - RemovalListener:監(jiān)聽器接口,用于監(jiān)聽緩存項(xiàng)的移除事件,可以實(shí)現(xiàn)一些清理工作或日志記錄。
2. 創(chuàng)建Guava Cache
創(chuàng)建一個(gè)簡單的GuavaCache
可以通過CacheBuilder
來完成。以下是一個(gè)基本的例子:
import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import java.util.concurrent.TimeUnit; public class GuavaCacheExample { public static void main(String[] args) { // 創(chuàng)建一個(gè)最大容量為100,超過容量后使用LRU算法移除最近最少使用的條目, // 并且設(shè)置10分鐘后過期的緩存 Cache<String, String> cache = CacheBuilder.newBuilder() .maximumSize(100) .expireAfterWrite(10, TimeUnit.MINUTES) .removalListener(notification -> System.out.println("Removed: " + notification.getKey())) .build(); // 向緩存中添加數(shù)據(jù) cache.put("key1", "value1"); // 從緩存中獲取數(shù)據(jù) String value = cache.getIfPresent("key1"); System.out.println(value); // 輸出: value1 } }
3. 使用LoadingCache
LoadingCache
可以在緩存未命中時(shí)自動(dòng)加載數(shù)據(jù),這通常通過實(shí)現(xiàn)CacheLoader
來完成:
import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; public class LoadingCacheExample { public static void main(String[] args) throws ExecutionException { LoadingCache<String, String> cache = CacheBuilder.newBuilder() .maximumSize(100) .expireAfterWrite(10, TimeUnit.MINUTES) .build(new CacheLoader<String, String>() { @Override public String load(String key) throws Exception { return fetchFromDatabase(key); } }); // 獲取數(shù)據(jù),如果緩存中沒有,會(huì)自動(dòng)調(diào)用load方法加載 String value = cache.get("key1"); System.out.println(value); // 輸出: 從數(shù)據(jù)庫獲取的數(shù)據(jù) } private static String fetchFromDatabase(String key) { // 模擬從數(shù)據(jù)庫查詢 return "從數(shù)據(jù)庫獲取的數(shù)據(jù)"; } }
4. 高級特性
- 統(tǒng)計(jì)信息:通過
cache.stats()
可以獲得緩存的統(tǒng)計(jì)信息,如命中率、加載失敗次數(shù)等。 - 異步加載:可以使用
getUnchecked
或getAll
方法進(jìn)行異步加載,適合于耗時(shí)較長的操作。 - 刷新策略:通過
refreshAfterWrite
方法可以設(shè)置緩存項(xiàng)在寫入后的多久時(shí)間后刷新。
5. 注意事項(xiàng)
- 線程安全:Guava Cache是線程安全的,多線程環(huán)境下的讀寫操作不需要額外的同步控制。
- 內(nèi)存占用:雖然Guava Cache提供了多種策略來控制緩存大小,但在高并發(fā)場景下仍需注意內(nèi)存使用情況,避免因內(nèi)存溢出導(dǎo)致應(yīng)用崩潰。
- 過期策略:合理設(shè)置過期時(shí)間和清除策略,避免緩存中的數(shù)據(jù)長時(shí)間不更新,導(dǎo)致數(shù)據(jù)陳舊。
總結(jié)
通過使用 Guava Cache,我們可以有效地減少對數(shù)據(jù)庫的訪問次數(shù),提高系統(tǒng)的性能和響應(yīng)速度。特別是在高并發(fā)場景下,緩存的作用更加明顯。希望這個(gè)示例對你有所幫助!在處理高并發(fā)場景時(shí),緩存是提高系統(tǒng)性能和響應(yīng)速度的重要手段之一。Google Guava庫提供了一個(gè)非常強(qiáng)大的本地緩存實(shí)現(xiàn)——GuavaCache
,它不僅提供了基本的緩存功能,還支持多種高級特性,如過期策略、大小限制、統(tǒng)計(jì)信息等,非常適合在高并發(fā)環(huán)境下使用。
到此這篇關(guān)于java中的本地緩存GuavaCache使用方法和示例教程的文章就介紹到這了,更多相關(guān)java本地緩存GuavaCache內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java用20行代碼實(shí)現(xiàn)抖音小視頻批量轉(zhuǎn)換為gif動(dòng)態(tài)圖
這篇文章主要介紹了Java用20行代碼實(shí)現(xiàn)抖音小視頻批量轉(zhuǎn)換為gif動(dòng)態(tài)圖,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04java導(dǎo)出pdf文件的詳細(xì)實(shí)現(xiàn)方法
這篇文章主要介紹了java導(dǎo)出pdf文件的詳細(xì)實(shí)現(xiàn)方法,包括制作模板、獲取中文字體文件、實(shí)現(xiàn)后端服務(wù)以及前端發(fā)起請求并生成下載鏈接,需要的朋友可以參考下2025-03-03面試總結(jié):秒殺設(shè)計(jì)、AQS 、synchronized相關(guān)問題
Java語言的關(guān)鍵字,當(dāng)它用來修飾一個(gè)方法或者一個(gè)代碼塊的時(shí)候,能夠保證在同一時(shí)刻最多只有一個(gè)線程執(zhí)行該段代碼。本文給大家介紹java中 synchronized的用法,對本文感興趣的朋友一起看看吧2021-06-06ArrayList和JSONArray邊遍歷邊刪除到底該如何做
這篇文章主要介紹了ArrayList和JSONArray邊遍歷邊刪除到底該如何做,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-12-12Java中ByteBuddy動(dòng)態(tài)字節(jié)碼操作庫的使用技術(shù)指南
ByteBuddy?是一個(gè)功能強(qiáng)大的?Java?字節(jié)碼操作庫,可以幫助開發(fā)者在運(yùn)行時(shí)動(dòng)態(tài)生成和修改類,而無需直接接觸復(fù)雜的?ASM?API,本文給大家介紹了Java?ByteBuddy動(dòng)態(tài)字節(jié)碼操作庫的使用技術(shù)指南,需要的朋友可以參考下2025-04-04java中申請不定長度數(shù)組ArrayList的方法
今天小編就為大家分享一篇java中申請不定長度數(shù)組ArrayList的方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-07-07