java使用軟引用實現緩存機制示例
正文
“讀多寫少”是大部分項目的一個特點。例如“購物”,總是看的人多(讀)、買的人少(寫)。因此,如果能減少“讀”請求的次數,就能減少服務端的壓力。最直接的減少“讀”請求次數的方法就是使用緩存。
軟引用和強引用
對于同一個讀請求,只需要在第一次訪問時從數據庫中查詢數據,并將查詢到的數據保存到緩存中,之后的查詢請求就可以直接在緩存中獲取,從而減少對數據庫的訪問次數。
這種情況我們生活種經常會看到,比如訪問某app某商品,第一次進去會加載一會會,后面繼續(xù)點擊是直接出現。
根據目前所學知識,我們可以使用 HashMap 在內存級別實現緩存功能。
例如,可以使用一個 HashMap 對象保存客戶端第一次請求的結果,之后,當客戶端再次發(fā)起讀請求時,就從 HashMap 對象中遍歷查詢,如果 HashMap 中已經保存過客戶要查詢的數據,就直接返回,否則再向數據庫發(fā)起查詢請求,并將查詢結果保存到 HashMap 中。
這種緩存的設計思路十分簡單,但也存在一個問題:HashMap 中緩存的數據何時被清空?
內存容量是有限制的,如果永無止盡的向 HashMap 緩存數據,顯然會對內存容量帶來壓力。一種解決方案就是使用 JVM 提供的軟引用,實現對 HashMap 中緩存數據的淘汰策略。
開發(fā)中最常使用的是強引用,例如 Goods goods = new Goods()
就創(chuàng)建了一個強引用對象“goods”。只要強引用的作用域沒有結束,或者沒有被開發(fā)者手工設置為 null,那么強引用對象會始終存在于 JVM 內存中。
而 JVM 提供的軟引用就比較靈活:當 JVM 的內存足夠時,GC 對待軟引用和強引用的方式是一樣的;但當 JVM 的內存不足時,GC 就會去主動回收軟引用對象。
可見,非常適合將緩存的對象存放在軟引用中。軟引用需要借助 JDK 提供的 java.lang.ref.SoftReference
類來實現。
項目
使用idea創(chuàng)建一個maven項目
結構如下
首先對Good實體類進行編寫。
要求,goods有屬性id,name并書寫他的getset方法,以及有參無參構造器。
這里代碼省略。
然后我們在goodbase里面編寫代碼,模擬一個數據庫
里面主要有hashmap,并且通過get方法,得到該hashmap
public class GoodsBase { private static Map<String, Goods> base = new HashMap<>(); public static Map<String, Goods> getBase() { return base; } }
然后書寫goodscache緩存類
這里我們需要接觸一個新關鍵字volatile
- 使用volatile關鍵字會強制將修改的值立即寫入主存;
- 使用volatile關鍵字的話,當主線程修改時,會導致RunThread的工作內存中isRunning變量的緩存值變得無效。
- 由于RunThread的工作內存中緩存變量isRunning緩存無效,所以會再次從主存中讀取isRunning變量值。
在map里面通過泛型把緩存對象存儲在軟引用里面(map里面)
代碼如下:
public class GoodsCache { private volatile static GoodsCache goodsCache; public GoodsCache(){ this.cache = new HashMap<>(); } public static GoodsCache getGoodsCache() { if(goodsCache == null) { synchronized (GoodsCache.class){ if(goodsCache == null){ goodsCache = new GoodsCache(); } } } return goodsCache; } // 將緩存對象存儲在軟引用中 private Map<String, SoftReference<Goods>> cache; // 根據id存儲緩存Goods對象 public void setCache(Goods goods) { cache.put(goods.getId(), new SoftReference<Goods>(goods)); System.out.println("添加數據到緩存成功"); } // 根據id從緩存中獲取對象 public Goods getCache(String id) { // 根據id,獲取緩存對象的軟引用 SoftReference<Goods> softRef = cache.get(id); return softRef == null ? null : softRef.get(); } public void delCache(String id) { cache.remove(id); System.out.println("從緩存刪除數據成功"); } }
goodsservice模擬數據庫增刪改查
接下來我們書寫goodsservice代碼,來模擬數據庫增刪改查,不過我們是通過id來進行
public class GoodsService { GoodsCache goodsCache = GoodsCache.getGoodsCache(); public Goods getById(String id){ if(goodsCache.getCache(id) == null){ Goods goods = GoodsBase.getBase().get(id); goodsCache.setCache(goods); System.out.println("從數據庫讀取數據"); System.out.println(goods.getName()); return goods; } System.out.println(goodsCache.getCache(id).getName()); return goodsCache.getCache(id); } public void add(Goods goods){ goodsCache.setCache(goods); GoodsBase.getBase().put(goods.getId(), goods); System.out.println("添加數據到數據庫"); } public void deleteById(String id){ if(goodsCache.getCache(id) != null){ goodsCache.delCache(id); } GoodsBase.getBase().remove(id); } }
最后我們書寫test文件
運行結果
可以看到第二次運行 goodsService.getById("1");
是從緩存中直接讀取的數據,也可以看出,其實用軟引用實現緩存機制,讀取的對象是同一個對象。
以上就是java使用軟引用實現緩存機制示例的詳細內容,更多關于java軟引用緩存機制的資料請關注腳本之家其它相關文章!
相關文章
Java(TM) Platform SE binary 打開jar文件的操作
這篇文章主要介紹了Java(TM) Platform SE binary 打開jar文件的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-02-02在IDEA中搭建最小可用SpringMVC項目(純Java配置)
這篇文章主要介紹了在IDEA中搭建最小可用SpringMVC項目(純Java配置),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-12-12Spring中@PropertySource注解使用場景解析
這篇文章主要介紹了Spring中@PropertySource注解使用場景解析,@PropertySource注解就是Spring中提供的一個可以加載配置文件的注解,并且可以將配置文件中的內容存放到Spring的環(huán)境變量中,需要的朋友可以參考下2023-11-11