欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java設(shè)置Map過(guò)期時(shí)間的的幾種方法舉例詳解

 更新時(shí)間:2024年10月14日 09:52:23   作者:虞澤  
本文詳細(xì)介紹了Java中使用輕量級(jí)緩存組件ExpiringMap以及Guava的LoadingCache緩存機(jī)制,ExpiringMap提供了Map自動(dòng)過(guò)期、監(jiān)聽(tīng)事件等功能,而LoadingCache提供了緩存回收、數(shù)據(jù)加載等高級(jí)功能,兩者為Java項(xiàng)目提供了有效的數(shù)據(jù)管理和緩存解決方案,需要的朋友可以參考下

一、技術(shù)背景

在實(shí)際的項(xiàng)目開(kāi)發(fā)中,我們經(jīng)常會(huì)使用到緩存中間件(如redis、MemCache等)來(lái)幫助我們提高系統(tǒng)的可用性和健壯性。

但是很多時(shí)候如果項(xiàng)目比較簡(jiǎn)單,就沒(méi)有必要為了使用緩存而專門引入Redis等等中間件來(lái)加重系統(tǒng)的復(fù)雜性。那么使用Java本身自己的輕量級(jí)的緩存組件就是完美解決方式。

二、技術(shù)效果

  • 實(shí)現(xiàn)緩存的常見(jiàn)功能
  • 熱點(diǎn)數(shù)據(jù)預(yù)熱
  • 簡(jiǎn)單限流
  • 去重

三、ExpiringMap

3.1 ExpiringMap簡(jiǎn)介

ExpiringMap具有高性能、低開(kāi)銷、零依賴、線程安全、使用 ConcurrentMap 的實(shí)現(xiàn)過(guò)期 entries 等優(yōu)點(diǎn)。
功能包括不限于:

  • 設(shè)置 Map 中的 Entry 在一段時(shí)間后自動(dòng)過(guò)期。
  • 設(shè)置 Map 最大容納值,當(dāng)?shù)竭_(dá) Max size 后,再次插入值會(huì)導(dǎo)致 Map 中的第一個(gè)值過(guò)期。
  • 設(shè)置 添加監(jiān)聽(tīng)事件,在監(jiān)聽(tīng)到 Entry 過(guò)期時(shí)調(diào)度監(jiān)聽(tīng)函數(shù)。
  • 設(shè)置懶加載,在調(diào)用 get() 方法時(shí)創(chuàng)建對(duì)象。
  • 允許您了解條目預(yù)計(jì)何時(shí)過(guò)期

3.2 ExpiringMap使用

3.2.1 pom.xml 中添加依賴

        <!-- https://mvnrepository.com/artifact/net.jodah/expiringmap -->
        <dependency>
            <groupId>net.jodah</groupId>
            <artifactId>expiringmap</artifactId>
            <version>0.5.10</version>
        </dependency>

3.2.2 代碼中使用

    /**
     * ① maxSize:Map存儲(chǔ)的最大值,類似隊(duì)列,容量固定,當(dāng)操作map容量超出限制時(shí),最開(kāi)始的元素就會(huì)依次過(guò)期,只保留最新的;
     * ② expiration:過(guò)期時(shí)間;
     * ③ expirationListener:過(guò)期監(jiān)聽(tīng),當(dāng)條目過(guò)期時(shí),將同步調(diào)用過(guò)期偵聽(tīng)器,并且在偵聽(tīng)器完成之前,
     *  將阻止對(duì)映射的寫入操作。還可以在單獨(dú)的線程池中配置和調(diào)用異步過(guò)期偵聽(tīng)器,而不會(huì)阻塞映射操作;
     * ④ expirationPolicy:過(guò)期策略,包括 ExpirationPolicy.ACCESSED 和 ExpirationPolicy.CREATED 兩種;
     *      1)ExpirationPolicy.ACCESSED :每進(jìn)行一次訪問(wèn),過(guò)期時(shí)間就會(huì)自動(dòng)清零,重新計(jì)算;
     *      2)ExpirationPolicy.CREATED:在過(guò)期時(shí)間內(nèi)重新 put 值的話,過(guò)期時(shí)間會(huì)清理,重新計(jì)算;
     * ⑤ variableExpiration:可變過(guò)期,條目可以具有單獨(dú)可變的到期時(shí)間和策略:
     */
    public static  ExpiringMap<String, String> map = ExpiringMap.builder()
            .maxSize(1000)
            .expiration(2, TimeUnit.HOURS)
            .variableExpiration()
            .expirationPolicy(ExpirationPolicy.ACCESSED)
            .expirationListener((key, value) -> {
                System.out.println("SseEmitter已過(guò)期,key:"+ key);
            })
            .build();

3.2.3 參數(shù)說(shuō)明

 ① maxSize:Map存儲(chǔ)的最大值,類似隊(duì)列,容量固定,當(dāng)操作map容量超出限制時(shí),最開(kāi)始的元素就會(huì)依次過(guò)期,只保留最新的;
 ② expiration:過(guò)期時(shí)間;
 ③ expirationListener:過(guò)期監(jiān)聽(tīng),當(dāng)條目過(guò)期時(shí),將同步調(diào)用過(guò)期偵聽(tīng)器,并且在偵聽(tīng)器完成之前,
  將阻止對(duì)映射的寫入操作。還可以在單獨(dú)的線程池中配置和調(diào)用異步過(guò)期偵聽(tīng)器,而不會(huì)阻塞映射操作;
 ④ expirationPolicy:過(guò)期策略,包括 ExpirationPolicy.ACCESSED 和 ExpirationPolicy.CREATED 兩種;
           1)ExpirationPolicy.ACCESSED :每進(jìn)行一次訪問(wèn),過(guò)期時(shí)間就會(huì)自動(dòng)清零,重新計(jì)算;
           2)ExpirationPolicy.CREATED:在過(guò)期時(shí)間內(nèi)重新 put 值的話,過(guò)期時(shí)間會(huì)清理,重新計(jì)算;
 ⑤ variableExpiration:可變過(guò)期,條目可以具有單獨(dú)可變的到期時(shí)間和策略;

3.2.4 其他使用方式

		//為單個(gè)條目指定到期策略:
        map.put("1", "張三", ExpirationPolicy.CREATED);
        map.put("2", "李四", ExpirationPolicy.ACCESSED);

        //variableExpiration 可變過(guò)期 條目可以具有單獨(dú)可變的到期時(shí)間和策略:
        map.put("3", "王五", ExpirationPolicy.ACCESSED, 5, TimeUnit.MINUTES);

        //過(guò)期時(shí)間和策略也可以即時(shí)更改:
        map.setExpiration("1", 5, TimeUnit.MINUTES);
        map.setExpirationPolicy("1", ExpirationPolicy.ACCESSED);

        //動(dòng)態(tài)添加和刪除過(guò)期偵聽(tīng)器:
        ExpirationListener<String, String> connectionCloser = (key, value) -> System.out.println(key+":"+value);
        //添加偵聽(tīng)器
        map.addExpirationListener(connectionCloser);
        //移除偵聽(tīng)器
        map.removeExpirationListener(connectionCloser);

        //設(shè)置懶加載
//        Map<String, String> stringMap = ExpiringMap.builder()
//                .expiration(10, TimeUnit.MINUTES)
//                .entryLoader(address -> address)
//                .build();
//        // 通過(guò) EntryLoader 將值加載到map中
//        String value = stringMap.get("1");
//        System.out.println("value值:"+value);

        //獲取條目的到期時(shí)間:?jiǎn)挝?毫秒
        long expiration = map.getExpectedExpiration("1");
        System.out.println("距離過(guò)期時(shí)間還有:"+expiration+"毫秒");

        //重置條目的內(nèi)部到期計(jì)時(shí)器:
        map.resetExpiration("1");

        //查看設(shè)置的過(guò)期時(shí)間
        map.getExpiration("1");
        System.out.println("設(shè)置的過(guò)期時(shí)間:"+map.getExpiration("1"));
        

測(cè)試結(jié)果

距離過(guò)期時(shí)間還有:299999毫秒
設(shè)置的過(guò)期時(shí)間:300000

四、Guava的LoadingCache

4.1 LoadingCache簡(jiǎn)介

做java的我們都知道Guava是一個(gè)編程工具類庫(kù),其中包含了很多高質(zhì)量高性能的工具類和方法。其中,LoadingCache便是一個(gè)特別好用的功能,其背后的架構(gòu)其實(shí)就是Guava cache,Guava Cache 是一個(gè)全內(nèi)存的本地緩存實(shí)現(xiàn),它提供了線程安全的實(shí)現(xiàn)機(jī)制,它可以加載緩存中不存在的數(shù)據(jù),本質(zhì)其實(shí)是一個(gè)鍵值對(duì)(key-value)的緩存,可以通過(guò)key獲取到對(duì)應(yīng)的緩存值value。
特點(diǎn):提供緩存回收機(jī)制,監(jiān)控緩存加載/命中情況,靈活強(qiáng)大的功能,簡(jiǎn)單易上手的api。

4.2 LoadingCache使用

4.2.1 pom.xml 中添加依賴

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

4.2.2 代碼中使用

	public static LoadingCache<Long, User> userCache= CacheBuilder.newBuilder()
            // 緩存池大小,在緩存數(shù)量到達(dá)該大小時(shí), 開(kāi)始回收舊的數(shù)據(jù)
            .maximumSize(1000)
            // 設(shè)置時(shí)間60s對(duì)象沒(méi)有被讀/寫訪問(wèn)則對(duì)象從內(nèi)存中刪除
            .expireAfterAccess(60, TimeUnit.SECONDS)
            // 設(shè)置緩存在寫入之后 設(shè)定時(shí)間60s后失效
            .expireAfterWrite(60, TimeUnit.SECONDS)
            // 定時(shí)刷新,設(shè)置時(shí)間10s后,當(dāng)有訪問(wèn)時(shí)會(huì)重新執(zhí)行l(wèi)oad方法重新加載
            .refreshAfterWrite(10, TimeUnit.SECONDS)
            // 移除監(jiān)聽(tīng)器,緩存項(xiàng)被移除時(shí)會(huì)觸發(fā)
            .removalListener(new RemovalListener() {
                @Override
                public void onRemoval(RemovalNotification rn) {
                    // 處理緩存鍵不存在緩存值時(shí)的處理邏輯
                    log.error(rn.getKey() + "remove");
                }
            })
            // 處理緩存鍵對(duì)應(yīng)的緩存值不存在時(shí)的處理邏輯
            .build(new CacheLoader<Long, User>() {
                @Override
                public User load(Long id) {
                    return getById(id);
                }
    });
 
    public User getUser(Long id) {
        User user = userCache.get(id);
    }
 
    public ImmutableMap<Long, User > getAll(List<Long> ids) throws ExecutionException {
        return cache.getAll(ids);
    }

4.2.3 參數(shù)說(shuō)明

 ① maximumSize:緩存的k-v最大數(shù)據(jù),當(dāng)總緩存的數(shù)據(jù)量達(dá)到這個(gè)值時(shí),就會(huì)淘汰它認(rèn)為不太用的一份數(shù)據(jù),會(huì)使用LRU策略進(jìn)行回收;
 ② expireAfterAccess:緩存項(xiàng)在給定時(shí)間內(nèi)沒(méi)有被讀/寫訪問(wèn),則回收,這個(gè)策略主要是為了淘汰長(zhǎng)時(shí)間不被訪問(wèn)的數(shù)據(jù);
 ③ expireAfterWrite:緩存項(xiàng)在給定時(shí)間內(nèi)沒(méi)有被寫訪問(wèn)(創(chuàng)建或覆蓋),則回收, 防止舊數(shù)據(jù)被緩存過(guò)久;
 ④ refreshAfterWrite:緩存項(xiàng)在給定時(shí)間內(nèi)沒(méi)有被寫訪問(wèn)(創(chuàng)建或覆蓋),則刷新;
 ⑤ recordStats:開(kāi)啟Cache的狀態(tài)統(tǒng)計(jì)(默認(rèn)是開(kāi)啟的);

4.2.4 GET方法

  V get(K key, int hash, CacheLoader<? super K, V> loader) throws ExecutionException {
    try {
      if (count != 0) { // read-volatile
        ReferenceEntry<K, V> e = getEntry(key, hash);
        if (e != null) {
          long now = map.ticker.read();
          //檢查entry是否符合expireAfterAccess淘汰策略
          V value = getLiveValue(e, now);
          // value是有效的 則返回
          if (value != null) {
            // 記錄該值的最近訪問(wèn)時(shí)間
            recordRead(e, now);
            statsCounter.recordHits(1);
            // 內(nèi)部實(shí)現(xiàn)了定時(shí)刷新,若未開(kāi)啟refreshAfterWrite則直接返回value
            return scheduleRefresh(e, key, hash, value, now, loader);
          }
          ValueReference<K, V> valueReference = e.getValueReference();
          // 如果有別的線程已經(jīng)在load value,則等到其他線程完成后再取結(jié)果
          if (valueReference.isLoading()) {
            return waitForLoadingValue(e, key, valueReference);
          }
        }
      }
 
      // 如果沒(méi)拿到有效的value,則執(zhí)行加載邏輯;
      return lockedGetOrLoad(key, hash, loader);
    } catch (ExecutionException ee) {
      ...
    } finally {
      postReadCleanup();
    }
  }

4.2.5 Load方法

@GwtCompatible(emulated = true)
public abstract class CacheLoader<K, V> {
 
  public abstract V load(K key) throws Exception;
 
}

4.3 移除機(jī)制

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

  • 被動(dòng)移除
  • 基于大小的移除:數(shù)量達(dá)到指定大小,會(huì)把不常用的鍵值移除
  • 基于時(shí)間的移除:expireAfterAccess(long, TimeUnit) 根據(jù)某個(gè)鍵值對(duì)最后一次訪問(wèn)之后多少時(shí)間后移除。expireAfterWrite(long, TimeUnit) 根據(jù)某個(gè)鍵值對(duì)被創(chuàng)建或值被替換后多少時(shí)間移除
  • 基于引用的移除:主要是基于java的垃圾回收機(jī)制,根據(jù)鍵或者值的引用關(guān)系決定移除
  • 主動(dòng)移除
  • 單獨(dú)移除:Cache.invalidate(key)
  • 批量移除:Cache.invalidateAll(keys)
  • 移除所有:Cache.invalidateAll()

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

4.4 其他

  • 在put操作之前,如果已經(jīng)有該鍵值,會(huì)先觸發(fā)removalListener移除監(jiān)聽(tīng)器,再添加
  • 配置了expireAfterAccess和expireAfterWrite,但在指定時(shí)間后沒(mé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)槭紫染€程相對(duì)較重,其次某些環(huán)境限制線程的創(chuàng)建。

它會(huì)在寫操作時(shí)順帶做少量的維護(hù)工作,或者偶爾在讀操作時(shí)做。當(dāng)然,也可以創(chuàng)建自己的維護(hù)線程,以固定的時(shí)間間隔調(diào)用Cache.cleanUp()。

總結(jié)

到此這篇關(guān)于Java設(shè)置Map過(guò)期時(shí)間的的幾種方法的文章就介紹到這了,更多相關(guān)Java設(shè)置Map過(guò)期時(shí)間內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java 中校驗(yàn)時(shí)間格式的常見(jiàn)方法

    Java 中校驗(yàn)時(shí)間格式的常見(jiàn)方法

    在實(shí)際項(xiàng)目開(kāi)發(fā)中,跟時(shí)間參數(shù)打交道是必不可少的,為了保證程序的安全性、健壯性,一般都會(huì)對(duì)參數(shù)進(jìn)行校驗(yàn),其他類型的參數(shù)校驗(yàn)很好實(shí)現(xiàn),那你知道時(shí)間參數(shù)的是怎么校驗(yàn)的嗎,下面給大家分享Java 中校驗(yàn)時(shí)間格式的方法,感興趣的朋友跟隨小編一起看看吧
    2024-08-08
  • SpringBoot使用swagger生成api接口文檔的方法詳解

    SpringBoot使用swagger生成api接口文檔的方法詳解

    在之前的文章中,使用mybatis-plus生成了對(duì)應(yīng)的包,在此基礎(chǔ)上,我們針對(duì)項(xiàng)目的api接口,添加swagger配置和注解,生成swagger接口文檔,需要的可以了解一下
    2022-10-10
  • springboot項(xiàng)目快速搭建的方法步驟

    springboot項(xiàng)目快速搭建的方法步驟

    這篇文章主要介紹了springboot項(xiàng)目快速搭建的方法步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • Java面向?qū)ο笾甪inal關(guān)鍵字詳細(xì)解讀

    Java面向?qū)ο笾甪inal關(guān)鍵字詳細(xì)解讀

    這篇文章主要介紹了Java面向?qū)ο笾甪inal關(guān)鍵字詳細(xì)解讀,final修飾的屬性又叫常量,一般用 XX_XX_XX來(lái)命名,final修飾的屬性在定義時(shí)必須賦初始值,并且以后不能再修改,需要的朋友可以參考下
    2024-01-01
  • 利用Java正則表達(dá)式校驗(yàn)郵箱與手機(jī)號(hào)

    利用Java正則表達(dá)式校驗(yàn)郵箱與手機(jī)號(hào)

    利用Java正則表達(dá)式校驗(yàn)郵箱與手機(jī)號(hào)。需要的朋友可以過(guò)來(lái)參考下,希望對(duì)大家有所幫助
    2013-10-10
  • 使用SpringBoot中web項(xiàng)目推薦目錄結(jié)構(gòu)的問(wèn)題

    使用SpringBoot中web項(xiàng)目推薦目錄結(jié)構(gòu)的問(wèn)題

    這篇文章主要介紹了SpringBoot中web項(xiàng)目推薦目錄結(jié)構(gòu)的問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-01-01
  • Mybatis 中的sql批量修改方法實(shí)現(xiàn)

    Mybatis 中的sql批量修改方法實(shí)現(xiàn)

    在項(xiàng)目中遇到需要批量更新的功能,原本想的是在Java中用循環(huán)訪問(wèn)數(shù)據(jù)庫(kù)去更新,但是心里總覺(jué)得這樣做會(huì)不會(huì)太頻繁了,太耗費(fèi)資源了,效率也很低,查了下mybatis的批量操作,原來(lái)確實(shí)有<foreach>標(biāo)簽可以做到,下面通過(guò)本文給大家介紹下
    2017-01-01
  • Java數(shù)組擴(kuò)容的三大小結(jié)

    Java數(shù)組擴(kuò)容的三大小結(jié)

    當(dāng)數(shù)組需要容納更多元素時(shí),可以通過(guò)擴(kuò)容來(lái)增加其容量,本文主要介紹了Java數(shù)組擴(kuò)容的三大小結(jié),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-08-08
  • Spring Boot構(gòu)建優(yōu)雅的RESTful接口過(guò)程詳解

    Spring Boot構(gòu)建優(yōu)雅的RESTful接口過(guò)程詳解

    這篇文章主要介紹了spring boot構(gòu)建優(yōu)雅的RESTful接口過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-08-08
  • packages思維及使用Java添加Android平臺(tái)特定實(shí)現(xiàn)

    packages思維及使用Java添加Android平臺(tái)特定實(shí)現(xiàn)

    這篇文章主要為大家介紹了packages思維及使用Java添加Android平臺(tái)特定實(shí)現(xiàn)在Flutter框架里的體現(xiàn)和運(yùn)用詳解,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12

最新評(píng)論