您的位置:首页 > 教育 > 培训 > 网站推广的资源合作推广_详情页用什么软件制作_查找关键词的工具叫什么_接广告的平台

网站推广的资源合作推广_详情页用什么软件制作_查找关键词的工具叫什么_接广告的平台

2025/1/9 16:20:27 来源:https://blog.csdn.net/m0_61949623/article/details/145004152  浏览:    关键词:网站推广的资源合作推广_详情页用什么软件制作_查找关键词的工具叫什么_接广告的平台
网站推广的资源合作推广_详情页用什么软件制作_查找关键词的工具叫什么_接广告的平台

1、不足

以前的设计非常简单,符合最基本的思路,就是将过期的信息放在一个 map 中,然后去遍历清空。

为了避免单次操作时间过长,类似 redis,单次操作 100 个元素之后,直接返回。

(1)keys 的选择不够随机,可能会导致每次循环 100 个结束时,真正需要过期的没有被遍历到。

(2)keys 的遍历可能大部分都是无效的。我们每次都是根据 keys 从前往后遍历,但是没有关心对应的过期时间,所以导致很多无效遍历。

2、基本属性定义

public class CacheExpireSort<K,V> implements ICacheExpire<K,V> {/*** 单次清空的数量限制* @since 0.0.3*/private static final int LIMIT = 100;/*** 排序缓存存储** 使用按照时间排序的缓存处理。* @since 0.0.3*/private final Map<Long, List<K>> sortMap = new TreeMap<>(new Comparator<Long>() {@Overridepublic int compare(Long o1, Long o2) {return (int) (o1-o2);}});/*** 过期 map** 空间换时间* @since 0.0.3*/private final Map<K, Long> expireMap = new HashMap<>();/*** 缓存实现* @since 0.0.3*/private final ICache<K,V> cache;}

3、放入元素时

@Override
public void expire(K key, long expireAt) {List<K> keys = sortMap.get(expireAt);if(keys == null) {keys = new ArrayList<>();}keys.add(key);// 设置对应的信息sortMap.put(expireAt, keys);expireMap.put(key, expireAt);
}

每次存入新元素时,同时放入 sortMap 和 expireMap。

4、定时任务的执行

/*** 线程执行类* @since 0.0.3*/
private static final ScheduledExecutorService EXECUTOR_SERVICE = Executors.newSingleThreadScheduledExecutor();public CacheExpireSort(ICache<K, V> cache) {this.cache = cache;this.init();
}
/*** 初始化任务* @since 0.0.3*/
private void init() {EXECUTOR_SERVICE.scheduleAtFixedRate(new ExpireThread(), 100, 100, TimeUnit.MILLISECONDS);
}

5、执行任务

/*** 定时执行任务* @since 0.0.3*/
private class ExpireThread implements Runnable {@Overridepublic void run() {//1.判断是否为空if(MapUtil.isEmpty(sortMap)) {return;}//2. 获取 key 进行处理int count = 0;for(Map.Entry<Long, List<K>> entry : sortMap.entrySet()) {final Long expireAt = entry.getKey();List<K> expireKeys = entry.getValue();// 判断队列是否为空if(CollectionUtil.isEmpty(expireKeys)) {sortMap.remove(expireAt);continue;}if(count >= LIMIT) {return;}// 删除的逻辑处理long currentTime = System.currentTimeMillis();if(currentTime >= expireAt) {Iterator<K> iterator = expireKeys.iterator();while (iterator.hasNext()) {K key = iterator.next();// 先移除本身iterator.remove();expireMap.remove(key);// 再移除缓存,后续可以通过惰性删除做补偿cache.remove(key);count++;}} else {// 直接跳过,没有过期的信息return;}}}
}

这里直接遍历 sortMap,对应的 key 就是过期时间,然后和当前时间对比即可。

删除的时候,需要删除 expireMap/sortMap/cache。

6、惰性删除刷新

@Override
public void refreshExpire(Collection<K> keyList) {if(CollectionUtil.isEmpty(keyList)) {return;}// 这样维护两套的代价太大,后续优化,暂时不用。// 判断大小,小的作为外循环final int expireSize = expireMap.size();if(expireSize <= keyList.size()) {// 一般过期的数量都是较少的for(Map.Entry<K,Long> entry : expireMap.entrySet()) {K key = entry.getKey();// 这里直接执行过期处理,不再判断是否存在于集合中。// 因为基于集合的判断,时间复杂度为 O(n)this.removeExpireKey(key);}} else {for(K key : keyList) {this.removeExpireKey(key);}}
}/*** 移除过期信息* @param key key* @since 0.0.10*/
private void removeExpireKey(final K key) {Long expireTime = expireMap.get(key);if(expireTime != null) {final long currentTime = System.currentTimeMillis();if(currentTime >= expireTime) {expireMap.remove(key);List<K> expireKeys = sortMap.get(expireTime);expireKeys.remove(key);sortMap.put(expireTime, expireKeys);}}
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com