基于Infinispan的Java应用在线用户数统计并发问题求助
解决Infinispan在线用户数统计的并发同步问题
问题根源
你遇到的是典型的读-改-写竞态条件:多个并发请求同时读取缓存中的用户数,各自加1后写回,导致最终计数比实际登录用户数少(比如两个请求同时读10,都写11,实际应该是12)。
解决方案
Infinispan提供了原生原子操作API来规避这类问题,以下是几种可靠实现方式:
1. 使用compute()原子方法
Infinispan的AdvancedCache提供的compute()方法,会在缓存条目上执行原子计算逻辑,确保读-改-写全程线程安全:
// 获取AdvancedCache实例 AdvancedCache<String, Integer> advancedCache = cache.getAdvancedCache(); // 原子更新在线用户数 Integer newCount = advancedCache.compute("online-users", (key, currentValue) -> { // 初始状态(无缓存值)从0开始计数 return (currentValue == null) ? 1 : currentValue + 1; });
该方法会自动处理锁机制,同一时间仅允许一个线程修改目标缓存条目,彻底消除竞态条件。
2. 使用merge()方法(适合初始值明确场景)
如果默认初始值固定为0,可使用merge()方法合并现有值与增量,内部同样是原子操作:
// 每次登录时,现有值加1,无值则从0+1开始 Integer newCount = cache.merge("online-users", 1, (existing, valueToAdd) -> existing + valueToAdd);
3. 分布式锁(自定义复杂场景)
若需更灵活的业务逻辑控制,可手动获取分布式锁保护读-改-写流程:
// 获取分布式锁管理器 LockManager lockManager = advancedCache.getLockManager(); // 锁定目标缓存键 lockManager.lock("online-users"); try { Integer currentCount = cache.get("online-users"); Integer newCount = (currentCount == null) ? 1 : currentCount + 1; cache.put("online-users", newCount); } finally { // 必须在finally块释放锁,避免死锁 lockManager.unlock("online-users"); }
额外注意事项
- 登出操作需复用相同原子方法(比如
compute()中减1),避免登出环节出现并发问题。 - 集群环境下,Infinispan原子操作会自动同步所有节点,无需额外处理一致性。
- 绝对避免单独使用
get()+put()组合,这种非原子操作在并发场景下必然导致数据不一致。
内容的提问来源于stack exchange,提问作者Gagan
相关产品推荐
相关产品推荐

