Guava Cache达到maximumSize时如何执行自定义逻辑而非移除旧元素?
解决Guava Cache实现连接限制时的自定义拦截逻辑问题
要实现缓存达到上限时拦截新连接(而非自动移除旧元素),核心是不要依赖Guava Cache的自动驱逐机制,而是手动控制元素添加逻辑,在添加前判断当前连接数是否已达上限。以下是具体实现方案:
方案思路
- 放弃
maximumSize的自动驱逐,改用原子计数器精确追踪当前连接数 - 结合Guava Cache的
removalListener,在元素过期或被移除时自动递减计数器,保证计数准确性 - 在处理新连接时,先尝试递增计数器,若超过上限则执行拦截逻辑,否则将玩家加入缓存
代码实现
import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.cache.RemovalListener; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; // 初始化计数器与缓存 AtomicInteger currentConnectionCount = new AtomicInteger(0); Cache<String, Player> connectionCache = CacheBuilder.newBuilder() .expireAfterWrite(1, TimeUnit.SECONDS) .removalListener((RemovalListener<String, Player>) notification -> { // 元素过期/被移除时,计数器减一 currentConnectionCount.decrementAndGet(); }) .build(); // 处理玩家连接的核心方法 public boolean handlePlayerConnection(Player player) { String playerId = player.getId(); int maxConnections = instance.getSettings().getInt("CONNECTION-PER-SEC"); // 尝试递增连接计数 int newCount = currentConnectionCount.incrementAndGet(); if (newCount > maxConnections) { // 超过上限,回滚计数并执行拦截 currentConnectionCount.decrementAndGet(); player.disconnect("连接过于频繁,请稍后再试"); return false; } // 检查玩家是否已在缓存中(避免重复连接导致计数错误) if (connectionCache.getIfPresent(playerId) != null) { currentConnectionCount.decrementAndGet(); return true; // 允许重复连接,或根据需求调整逻辑 } // 将玩家加入缓存 connectionCache.put(playerId, player); return true; }
关键说明
- 原子计数器
AtomicInteger保证了并发场景下计数的准确性,避免多线程竞争导致的计数错误 removalListener会在缓存元素因过期或手动移除时触发,确保计数器与缓存实际元素数同步- 不再使用
maximumSize,避免Guava自动驱逐旧元素,完全由我们控制连接数上限
内容的提问来源于stack exchange,提问作者Ixf1nity
相关产品推荐
相关产品推荐

