最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

如何基于LoadingCache實(shí)現(xiàn)Java本地緩存

 更新時(shí)間:2019年12月23日 09:29:02   作者:1024。  
這篇文章主要介紹了如何基于LoadingCache實(shí)現(xiàn)Java本地緩存,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下

這篇文章主要介紹了如何基于LoadingCache實(shí)現(xiàn)Java本地緩存,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下

前言

Guava是Google開(kāi)源出來(lái)的一套工具庫(kù)。其中提供的cache模塊非常方便,是一種與ConcurrentMap相似的緩存Map。

官方地址:https://github.com/google/guava/wiki/CachesExplained

開(kāi)始構(gòu)建

一. 添加依賴

<dependency>
  <groupId>com.google.guava</groupId>
  <artifactId>guava</artifactId>
  <version>27.1-jre</version>
</dependency>

二.創(chuàng)建 CacheLoader

LoadingCache<Long, String> cache = CacheBuilder.newBuilder()
        //緩存池大小,在緩存項(xiàng)接近該大小時(shí), Guava開(kāi)始回收舊的緩存項(xiàng)
        .maximumSize(GUAVA_CACHE_SIZE)
        //設(shè)置時(shí)間對(duì)象沒(méi)有被讀/寫訪問(wèn)則對(duì)象從內(nèi)存中刪除(在另外的線程里面不定期維護(hù))
        .expireAfterAccess(10, TimeUnit.MINUTES)
        //移除監(jiān)聽(tīng)器,緩存項(xiàng)被移除時(shí)會(huì)觸發(fā)
        .removalListener(new RemovalListener <Long, String>() {
          @Override
          public void onRemoval(RemovalNotification<Long, String> rn) {
            //執(zhí)行邏輯操作
          }
        })
        //開(kāi)啟Guava Cache的統(tǒng)計(jì)功能
        .recordStats()
        .build(cacheLoader);

三.個(gè)人封裝的工具類

package com.xxx;

import com.google.common.cache.*;
import org.slf4j.Logger;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;

public class CacheManager {

  private static Logger log = Log.get();

  /** 緩存項(xiàng)最大數(shù)量 */
  private static final long GUAVA_CACHE_SIZE = 100000;

  /** 緩存時(shí)間:天 */
  private static final long GUAVA_CACHE_DAY = 10;

  /** 緩存操作對(duì)象 */
  private static LoadingCache<Long, String> GLOBAL_CACHE = null;

  static {
    try {
      GLOBAL_CACHE = loadCache(new CacheLoader <Long, String>() {
        @Override
        public String load(Long key) throws Exception {
          // 處理緩存鍵不存在緩存值時(shí)的處理邏輯
          return "";
        }
      });
    } catch (Exception e) {
      log.error("初始化Guava Cache出錯(cuò)", e);
    }
  }

  /**
   * 全局緩存設(shè)置
   *
   * 緩存項(xiàng)最大數(shù)量:100000
   * 緩存有效時(shí)間(天):10
   *
   *
   * @param cacheLoader
   * @return
   * @throws Exception
   */
  private static LoadingCache<Long, String> loadCache(CacheLoader<Long, String> cacheLoader) throws Exception {
    LoadingCache<Long, String> cache = CacheBuilder.newBuilder()
        //緩存池大小,在緩存項(xiàng)接近該大小時(shí), Guava開(kāi)始回收舊的緩存項(xiàng)
        .maximumSize(GUAVA_CACHE_SIZE)
        //設(shè)置時(shí)間對(duì)象沒(méi)有被讀/寫訪問(wèn)則對(duì)象從內(nèi)存中刪除(在另外的線程里面不定期維護(hù))
        .expireAfterAccess(GUAVA_CACHE_DAY, TimeUnit.DAYS)
        // 設(shè)置緩存在寫入之后 設(shè)定時(shí)間 后失效
        .expireAfterWrite(GUAVA_CACHE_DAY, TimeUnit.DAYS)
        //移除監(jiān)聽(tīng)器,緩存項(xiàng)被移除時(shí)會(huì)觸發(fā)
        .removalListener(new RemovalListener <Long, String>() {
          @Override
          public void onRemoval(RemovalNotification<Long, String> rn) {
            //邏輯操作
          }
        })
        //開(kāi)啟Guava Cache的統(tǒng)計(jì)功能
        .recordStats()
        .build(cacheLoader);
    return cache;
  }

  /**
   * 設(shè)置緩存值
   * 注: 若已有該key值,則會(huì)先移除(會(huì)觸發(fā)removalListener移除監(jiān)聽(tīng)器),再添加
   *
   * @param key
   * @param value
   */
  public static void put(Long key, String value) {
    try {
      GLOBAL_CACHE.put(key, value);
    } catch (Exception e) {
      log.error("設(shè)置緩存值出錯(cuò)", e);
    }
  }

  /**
   * 批量設(shè)置緩存值
   *
   * @param map
   */
  public static void putAll(Map<? extends Long, ? extends String> map) {
    try {
      GLOBAL_CACHE.putAll(map);
    } catch (Exception e) {
      log.error("批量設(shè)置緩存值出錯(cuò)", e);
    }
  }

  /**
   * 獲取緩存值
   * 注:如果鍵不存在值,將調(diào)用CacheLoader的load方法加載新值到該鍵中
   *
   * @param key
   * @return
   */
  public static String get(Long key) {
    String token = "";
    try {
      token = GLOBAL_CACHE.get(key);
    } catch (Exception e) {
      log.error("獲取緩存值出錯(cuò)", e);
    }
    return token;
  }

    /**
   * 移除緩存
   *
   * @param key
   */
  public static void remove(Long key) {
    try {
      GLOBAL_CACHE.invalidate(key);
    } catch (Exception e) {
      log.error("移除緩存出錯(cuò)", e);
    }
  }

  /**
   * 批量移除緩存
   *
   * @param keys
   */
  public static void removeAll(Iterable<Long> keys) {
    try {
      GLOBAL_CACHE.invalidateAll(keys);
    } catch (Exception e) {
      log.error("批量移除緩存出錯(cuò)", e);
    }
  }

  /**
   * 清空所有緩存
   */
  public static void removeAll() {
    try {
      GLOBAL_CACHE.invalidateAll();
    } catch (Exception e) {
      log.error("清空所有緩存出錯(cuò)", e);
    }
  }

  /**
   * 獲取緩存項(xiàng)數(shù)量
   *
   * @return
   */
  public static long size() {
    long size = 0;
    try {
      size = GLOBAL_CACHE.size();
    } catch (Exception e) {
      log.error("獲取緩存項(xiàng)數(shù)量出錯(cuò)", e);
    }
    return size;
  }
}

總結(jié)

1.移除機(jī)制

guava做cache時(shí)候數(shù)據(jù)的移除分為被動(dòng)移除和主動(dòng)移除兩種。

被動(dòng)移除分為三種:1).基于大小的移除:數(shù)量達(dá)到指定大小,會(huì)把不常用的鍵值移除

         2).基于時(shí)間的移除:expireAfterAccess(long, TimeUnit) 根據(jù)某個(gè)鍵值對(duì)最后一次訪問(wèn)之后多少時(shí)間后移除
                   expireAfterWrite(long, TimeUnit) 根據(jù)某個(gè)鍵值對(duì)被創(chuàng)建或值被替換后多少時(shí)間移除

         3).基于引用的移除:主要是基于java的垃圾回收機(jī)制,根據(jù)鍵或者值的引用關(guān)系決定移除

主動(dòng)移除分為三種:1).單獨(dú)移除:Cache.invalidate(key)

         2).批量移除:Cache.invalidateAll(keys)

         3).移除所有:Cache.invalidateAll()

如果配置了移除監(jiān)聽(tīng)器RemovalListener,則在所有移除的動(dòng)作時(shí)會(huì)同步執(zhí)行該listener下的邏輯。

如需改成異步,使用:RemovalListeners.asynchronous(RemovalListener, Executor)

2.遇到的問(wèn)題

1). 在put操作之前,如果已經(jīng)有該鍵值,會(huì)先觸發(fā)removalListener移除監(jiān)聽(tīng)器,再添加

2). 配置了expireAfterAccess和expireAfterWrite,但在指定時(shí)間后沒(méi)有被移除。

解決方案:CacheBuilder在文檔上有說(shuō)明

If expireAfterWrite or expireAfterAccess is requested entries may be evicted on each cache modification, on occasional cache accesses, or on calls to Cache.cleanUp(). Expired entries may be counted in Cache.size(), but will never be visible to read or write operations.

翻譯過(guò)來(lái)大概的意思是:CacheBuilder構(gòu)建的緩存不會(huì)在特定時(shí)間自動(dòng)執(zhí)行清理和回收工作,也不會(huì)在某個(gè)緩存項(xiàng)過(guò)期后馬上清理,它不會(huì)啟動(dòng)一個(gè)線程來(lái)進(jìn)行緩存維護(hù),因?yàn)?/p>

a)線程相對(duì)較重

b)某些環(huán)境限制線程的創(chuàng)建。它會(huì)在寫操作時(shí)順帶做少量的維護(hù)工作,或者偶爾在讀操作時(shí)做

當(dāng)然,也可以創(chuàng)建自己的維護(hù)線程,以固定的時(shí)間間隔調(diào)用Cache.cleanUp()。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Fluent MyBatis實(shí)現(xiàn)動(dòng)態(tài)SQL

    Fluent MyBatis實(shí)現(xiàn)動(dòng)態(tài)SQL

    MyBatis 令人喜歡的一大特性就是動(dòng)態(tài) SQL。本文主要介紹了Fluent MyBatis實(shí)現(xiàn)動(dòng)態(tài)SQL,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • MyBatis的一級(jí)緩存和二級(jí)緩存以及優(yōu)點(diǎn)說(shuō)明

    MyBatis的一級(jí)緩存和二級(jí)緩存以及優(yōu)點(diǎn)說(shuō)明

    MyBatis的緩存機(jī)制包括一級(jí)緩存和二級(jí)緩存,一級(jí)緩存是SqlSession級(jí)別的緩存,開(kāi)啟默認(rèn),二級(jí)緩存是跨SqlSession的緩存,需要手動(dòng)開(kāi)啟和配置,二級(jí)緩存的優(yōu)點(diǎn)是減少數(shù)據(jù)庫(kù)訪問(wèn)、提高性能、降低負(fù)載和提高可擴(kuò)展性,同時(shí)需要注意緩存可能導(dǎo)致的數(shù)據(jù)不一致問(wèn)題
    2025-02-02
  • 深入了解Spring中Bean的作用域和生命周期

    深入了解Spring中Bean的作用域和生命周期

    這篇文章主要介紹了深入了解Spring中Bean的作用域和生命周期,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-10-10
  • Java數(shù)據(jù)存儲(chǔ)的“雙子星”對(duì)決(Map和Set的區(qū)別)

    Java數(shù)據(jù)存儲(chǔ)的“雙子星”對(duì)決(Map和Set的區(qū)別)

    文章主要介紹了Java中Map和Set兩種數(shù)據(jù)結(jié)構(gòu)的定義、實(shí)現(xiàn)、方法及應(yīng)用場(chǎng)景,Map用于存儲(chǔ)鍵值對(duì),鍵唯一,值可重復(fù);Set用于存儲(chǔ)唯一元素,無(wú)序,兩者都提供了豐富的操作方法,如添加、刪除、查找等,感興趣的朋友一起看看吧
    2025-02-02
  • Mybatis-Plus實(shí)現(xiàn)用戶ID自增出現(xiàn)的問(wèn)題解決

    Mybatis-Plus實(shí)現(xiàn)用戶ID自增出現(xiàn)的問(wèn)題解決

    項(xiàng)目基于 SpringBoot + MybatisPlus 3.5.2 使用數(shù)據(jù)庫(kù)自增ID時(shí), 出現(xiàn)重復(fù)鍵的問(wèn)題,本文就來(lái)介紹一下解決方法,感興趣的可以了解一下
    2023-09-09
  • Springmvc conver實(shí)現(xiàn)原理及用法解析

    Springmvc conver實(shí)現(xiàn)原理及用法解析

    這篇文章主要介紹了Springmvc conver實(shí)現(xiàn)原理及用法解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-10-10
  • Java文件操作之序列化與對(duì)象處理流詳解

    Java文件操作之序列化與對(duì)象處理流詳解

    這篇文章主要為大家詳細(xì)介紹了Java文件操作中的序列化與對(duì)象處理流,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2022-09-09
  • Scala之文件讀取、寫入、控制臺(tái)操作的方法示例

    Scala之文件讀取、寫入、控制臺(tái)操作的方法示例

    這篇文章主要介紹了Scala之文件讀取、寫入、控制臺(tái)操作的方法示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-06-06
  • idea切換分支的時(shí)候,忽略一些無(wú)用的修改設(shè)置

    idea切換分支的時(shí)候,忽略一些無(wú)用的修改設(shè)置

    這篇文章主要介紹了idea切換分支的時(shí)候,忽略一些無(wú)用的修改操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-02-02
  • java設(shè)計(jì)模式:建造者模式之生產(chǎn)線

    java設(shè)計(jì)模式:建造者模式之生產(chǎn)線

    這篇文章主要介紹了Java設(shè)計(jì)模式之建造者模式,結(jié)合具體實(shí)例形式分析了建造者模式的概念、原理、實(shí)現(xiàn)方法與相關(guān)使用注意事項(xiàng),需要的朋友可以參考下
    2021-08-08

最新評(píng)論

兰溪市| 高邑县| 广饶县| 刚察县| 永靖县| 金阳县| 汪清县| 察雅县| 辽阳市| 财经| 西乌珠穆沁旗| 大新县| 旌德县| 甘德县| 建平县| 梅州市| 天津市| 绩溪县| 龙山县| 合阳县| 遂平县| 京山县| 涪陵区| 自治县| 庄河市| 邳州市| 宁波市| 五莲县| 舞钢市| 青州市| 永城市| 恩施市| 舞钢市| 济阳县| 石首市| 阳谷县| 休宁县| 盖州市| 通道| 阜平县| 中宁县|