首頁 > 軟體

java使用軟參照實現快取機制範例

2022-08-07 14:02:24

正文

“讀多寫少”是大部分專案的一個特點。例如“購物”,總是看的人多(讀)、買的人少(寫)。因此,如果能減少“讀”請求的次數,就能減少伺服器端的壓力。最直接的減少“讀”請求次數的方法就是使用快取。

軟參照和強參照

對於同一個讀請求,只需要在第一次存取時從資料庫中查詢資料,並將查詢到的資料儲存到快取中,之後的查詢請求就可以直接在快取中獲取,從而減少對資料庫的存取次數。

這種情況我們生活種經常會看到,比如存取某app某商品,第一次進去會載入一會會,後面繼續點選是直接出現。

根據目前所學知識,我們可以使用 HashMap 在記憶體級別實現快取功能。

例如,可以使用一個 HashMap 物件儲存使用者端第一次請求的結果,之後,當用戶端再次發起讀請求時,就從 HashMap 物件中遍歷查詢,如果 HashMap 中已經儲存過客戶要查詢的資料,就直接返回,否則再向資料庫發起查詢請求,並將查詢結果儲存到 HashMap 中。

這種快取的設計思路十分簡單,但也存在一個問題:HashMap 中快取的資料何時被清空?

記憶體容量是有限制的,如果永無止盡的向 HashMap 快取資料,顯然會對記憶體容量帶來壓力。一種解決方案就是使用 JVM 提供的軟參照,實現對 HashMap 中快取資料的淘汰策略。

開發中最常使用的是強參照,例如 Goods goods = new Goods() 就建立了一個強參照物件“goods”。只要強參照的作用域沒有結束,或者沒有被開發者手工設定為 null,那麼強參照物件會始終存在於 JVM 記憶體中。

而 JVM 提供的軟參照就比較靈活:當 JVM 的記憶體足夠時,GC 對待軟參照和強參照的方式是一樣的;但當 JVM 的記憶體不足時,GC 就會去主動回收軟參照物件。

可見,非常適合將快取的物件存放在軟參照中。軟參照需要藉助 JDK 提供的 java.lang.ref.SoftReference 類來實現。

專案

使用idea建立一個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軟參照快取機制的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com