成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

本地緩存工具類

鄒立鵬 / 3075人閱讀

摘要:時(shí)間轉(zhuǎn)換成毫秒清空當(dāng)前命名空間下的所有暴露指定命名空間下所有的緩存死亡時(shí)間納秒值對(duì)更新緩存時(shí)舊的已有的會(huì)取消重新設(shè)置新的對(duì)于每個(gè)是單例的

package com.common.helper;


import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.lang.Nullable;

import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;

/**
 * 本地緩存管理器
 * 
 *     v1.1
 *       - getByNameSpace
 *       - isExpired(..) 判斷是否已經(jīng)死亡, 包含物理死亡和邏輯死亡.
 *
 *     v1.0
 *       - 增加構(gòu)造, 可指定線程數(shù)
 *
 *     v0.0.1
 *       - 測(cè)試期
 * 
* * @author Nisus Liu * @version 1.1 * @email [email protected] * @date 2018/11/7 17:55 */ @Slf4j public abstract class LocalCacheManager { public static final String NAMESPACE_KEY_JOIN = "::"; /** * 緩存池子 */ protected Map caches = new ConcurrentHashMap(); /** * 清除緩存的定時(shí)延遲任務(wù)(劊子手) */ protected Map headsmans = new ConcurrentHashMap(); protected ScheduledThreadPoolExecutor scheduler = new ScheduledThreadPoolExecutor(5); public LocalCacheManager() { } /** * @param poolSize 指定用于清除定時(shí)任務(wù)的線程數(shù) */ public LocalCacheManager(int poolSize) { scheduler.setCorePoolSize(poolSize); } /** * 獲取指定key的緩存值 * * @param key * @return */ public T get(@Nullable String nameSpace, String key) { if (StringUtil.isEmpty(key)) { return null; } if (!StringUtil.isEmpty(nameSpace)) { //key實(shí)際上是原生key加上命名空間前綴 key = joinNameSpaceAndKey(nameSpace, key); } if (isExpired(key)) return null; return caches.get(key); } /** * 判斷是否死亡(實(shí)際死亡/邏輯死亡) *

邏輯死亡: 時(shí)間上看已經(jīng)過期, 但是由于秦楚線程阻塞, 還沒有來得及清除

* * @param nskey joinNameSpaceAndKey * @return */ private boolean isExpired(String nskey) { //防止延遲清除任務(wù)阻塞, 導(dǎo)致生存時(shí)間誤差, 這里實(shí)現(xiàn)邏輯清除 Headsman headsman = headsmans.get(nskey); if (headsman != null) { //死亡時(shí)間 <= 當(dāng)前時(shí)間, 應(yīng)該設(shè)置為邏輯死亡, 返回null if (headsman.triggerTime <= System.nanoTime()) { // ?已經(jīng)邏輯死亡, 但實(shí)際沒有死亡的值是否要在這里清除呢? return true; } else { return false; } } // else: 物理死亡 return !caches.containsKey(nskey); } private String joinNameSpaceAndKey(String nameSpace, String key) { if (StringUtils.isBlank(key)) { log.debug("`key` is NULL, return"); return null; } if (!StringUtil.isEmpty(nameSpace)) { return nameSpace + NAMESPACE_KEY_JOIN + key; } return key; } /** * 增加OR更新緩存 * * @param key * @param value */ public boolean put(@Nullable String nameSpace, @NotNull String key, T value) { key = joinNameSpaceAndKey(nameSpace, key); if (key == null) { return false; } caches.put(key, value); return true; } /** * 更加OR更新緩存(可設(shè)置生存時(shí)間TTL,Time To Live) *
     *     Note: 注意避免并發(fā)對(duì)同一個(gè) key 設(shè)置TTL, 結(jié)果比較隨機(jī), 誰最后執(zhí)行, 就以誰的TTL設(shè)置為準(zhǔn).
     * 
* * @param key * @param value * @param ttl * @param unit */ @Deprecated public void put(@Nullable String nameSpace, String key, T value, long ttl, TimeUnit unit) { String nsKey = joinNameSpaceAndKey(nameSpace, key); put(null, nsKey, value); long triggerTime = System.nanoTime() + unit.toNanos(ttl); //若此 key 已經(jīng)有對(duì)應(yīng)的殺死任務(wù), 需要替換掉, 更新生存時(shí)間, 以最新的為準(zhǔn) Headsman headsman = headsmans.get(nsKey); if (headsman == null) { //增加緩存 headsman = new Headsman(); headsmans.put(nsKey, headsman); headsman.task = new Runnable() { @Override public void run() { //指定時(shí)間后清除此 nsKey T rm = caches.remove(nsKey); log.trace("cache expired, key: {}, value: {}", nsKey, rm); } }; } else { //更新緩存 //對(duì)于已經(jīng)有設(shè)置過緩存的 nsKey, 任務(wù)用已有的, scheduledFuture 先取消舊的, 在new新的 /*如果任務(wù)運(yùn)行之前調(diào)用了該方法,那么任務(wù)就不會(huì)被運(yùn)行; 如果任務(wù)已經(jīng)完成或者已經(jīng)被取消,那么該方法方法不起作用; 如果任務(wù)正在運(yùn)行,并且 cancel 傳入?yún)?shù)為 true,那么便會(huì)去終止與 Future 關(guān)聯(lián)的任務(wù)。*/ headsman.scheduledFuture.cancel(true); } headsman.scheduledFuture = new FutureTask(headsman.task, null); //時(shí)間轉(zhuǎn)換成毫秒 headsman.triggerTime = triggerTime; scheduler.schedule(headsman.scheduledFuture, ttl, unit); } public void put(@Nullable String nameSpace, String key, T value, Duration ttl) { String nsKey = joinNameSpaceAndKey(nameSpace, key); put(null, nsKey, value); long triggerTime = System.nanoTime() + ttl.toNanos(); //若此 key 已經(jīng)有對(duì)應(yīng)的殺死任務(wù), 需要替換掉, 更新生存時(shí)間, 以最新的為準(zhǔn) Headsman headsman = headsmans.get(nsKey); if (headsman == null) { //增加緩存 headsman = new Headsman(); headsmans.put(nsKey, headsman); headsman.task = new Runnable() { @Override public void run() { //指定時(shí)間后清除此 nsKey T rm = caches.remove(nsKey); log.trace("cache expired, key: {}, value: {}", nsKey, rm); } }; } else { //更新緩存 //對(duì)于已經(jīng)有設(shè)置過緩存的 nsKey, 任務(wù)用已有的, scheduledFuture 先取消舊的, 在new新的 /*如果任務(wù)運(yùn)行之前調(diào)用了該方法,那么任務(wù)就不會(huì)被運(yùn)行; 如果任務(wù)已經(jīng)完成或者已經(jīng)被取消,那么該方法方法不起作用; 如果任務(wù)正在運(yùn)行,并且 cancel 傳入?yún)?shù)為 true,那么便會(huì)去終止與 Future 關(guān)聯(lián)的任務(wù)。*/ headsman.scheduledFuture.cancel(true); } headsman.scheduledFuture = new FutureTask(headsman.task, null); //時(shí)間轉(zhuǎn)換成毫秒 headsman.triggerTime = triggerTime; scheduler.schedule(headsman.scheduledFuture, ttl.toMillis(), TimeUnit.MILLISECONDS); } public T evictCache(String nameSpace, String key) { if (key == null) { return null; } String nsKey = joinNameSpaceAndKey(nameSpace, key); Headsman hsm = headsmans.remove(nsKey); if (hsm != null) hsm.scheduledFuture.cancel(true); return caches.remove(nsKey); } /** * 清空當(dāng)前命名空間下的所有value */ public void evictCache(String nameSpace) { String prefix = nameSpace + NAMESPACE_KEY_JOIN; caches.forEach((k, v) -> { if (k.startsWith(prefix)) { evictCache(null, k); } }); } public void evictAllCache() { caches.clear(); } /** * 暴露指定命名空間下所有的緩存 * * @param nameSpace * @return */ public List getByNameSpace(String nameSpace) { String prefix = nameSpace + NAMESPACE_KEY_JOIN; List nsVals = new ArrayList<>(); caches.forEach((k, v) -> { if (k.startsWith(prefix)) { if (!isExpired(k)) { nsVals.add(v); } } }); return nsVals; } class Headsman { /** * 死亡時(shí)間, 納秒值 */ public long triggerTime; /** * 對(duì)key更新緩存時(shí), 舊的已有的會(huì)取消, 重新設(shè)置新的. */ public FutureTask scheduledFuture; /** * 對(duì)于每個(gè) key, task是單例的 */ public Runnable task; } }

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/75703.html

相關(guān)文章

  • 本地緩存工具

    摘要:時(shí)間轉(zhuǎn)換成毫秒清空當(dāng)前命名空間下的所有暴露指定命名空間下所有的緩存死亡時(shí)間納秒值對(duì)更新緩存時(shí)舊的已有的會(huì)取消重新設(shè)置新的對(duì)于每個(gè)是單例的 package com.common.helper; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.StringUtils; import org.jetbrai...

    RichardXG 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<