Java中是否存在CopyOnRead列表?写多读少的并发List实现咨询
适合写多场景的并发List替代方案
Java标准库中的CopyOnWriteArrayList是读多写少场景的优化实现,它在写操作(add/remove)时会复制整个底层数组,写操作频繁时内存开销大、性能极差,完全不适合你描述的写远多于读的场景。
针对你的Netty未登录连接管理场景(频繁添加、删除,定时清理),推荐以下两种更合适的方案:
1. 使用Netty自带的DefaultChannelGroup
这是最贴合Netty场景的选择,DefaultChannelGroup是线程安全的Channel集合,底层基于ConcurrentHashMap实现,并发写性能优异,还专门提供了Channel管理的便捷方法:
// 初始化ChannelGroup,使用全局事件循环处理异步操作 private final ChannelGroup unloggedConnections = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); // 连接成功时加入列表 public void onConnectionEstablished(Channel channel) { unloggedConnections.add(channel); } // 登录成功时从列表移除 public void onLoginSuccess(Channel channel) { unloggedConnections.remove(channel); } // 每30秒执行一次的清理任务 public void cleanUnloggedConnections() { // 移除不活跃的连接,以及已登录的连接 unloggedConnections.removeIf(channel -> { boolean isLoggedIn = channel.attr(AttributeKey.valueOf("LOGGED_IN")).getOrDefault(false); return !channel.isActive() || isLoggedIn; }); }
2. 使用ConcurrentHashMap手动维护
如果需要自定义键值映射(比如用用户标识而非Channel作为键),ConcurrentHashMap是更灵活的选择,它的put/remove操作都是O(1)复杂度,并发写性能远超CopyOnWriteArrayList:
// 用ChannelId作为键,存储未登录的Channel private final ConcurrentHashMap<ChannelId, Channel> unloggedConnections = new ConcurrentHashMap<>(); // 连接成功添加 public void onConnectionEstablished(Channel channel) { unloggedConnections.put(channel.id(), channel); } // 登录成功删除 public void onLoginSuccess(Channel channel) { unloggedConnections.remove(channel.id()); } // 定时清理逻辑 public void cleanUnloggedConnections() { unloggedConnections.entrySet().removeIf(entry -> { Channel channel = entry.getValue(); boolean isLoggedIn = channel.attr(AttributeKey.valueOf("LOGGED_IN")).getOrDefault(false); return !channel.isActive() || isLoggedIn; }); }
关键说明
- 不要使用
CopyOnWriteArrayList:写操作时的数组复制会导致频繁的内存分配和GC,在写远多于读的场景下性能会急剧下降。 - 优先选择
DefaultChannelGroup:它是Netty专为Channel管理设计的并发集合,内置了Channel活跃性检查等适配逻辑,代码更简洁。
内容的提问来源于stack exchange,提问作者gdrfgdrf
相关产品推荐
相关产品推荐

