如何实现首监听器添加连网、末监听器移除断网的线程安全集合?
解决方案:结合CopyOnWriteArraySet与AtomicInteger实现需求
你的场景核心是线程安全的监听器管理+读多写少优化+首尾元素变更时的触发逻辑,之前调研的两个方案各有不足,这里给你一个简洁且高效的实现思路:
核心思路
利用CopyOnWriteArraySet本身的读多写少优化、线程安全特性存储监听器,再配合AtomicInteger原子类跟踪监听器的数量——原子类能保证并发环境下计数的准确性,我们只需要在计数从0变1时触发网络初始化,从1变0时触发断开连接即可。
代码实现示例
import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.atomic.AtomicInteger; public class NetworkEventListenerManager { // 存储监听器的线程安全集合,读操作无锁,适合读多写少场景 private final CopyOnWriteArraySet<NetworkEventListener> listeners = new CopyOnWriteArraySet<>(); // 原子计数器,跟踪监听器数量,保证并发下计数准确 private final AtomicInteger listenerCount = new AtomicInteger(0); // 添加监听器方法 public void addListener(NetworkEventListener listener) { if (listener == null) { throw new IllegalArgumentException("Listener cannot be null"); } // 先尝试添加到集合(Set自动去重,重复添加不会改变集合) boolean added = listeners.add(listener); if (added) { int newCount = listenerCount.incrementAndGet(); // 当计数从0变为1时,初始化网络连接 if (newCount == 1) { initializeNetworkConnection(); } } } // 移除监听器方法 public void removeListener(NetworkEventListener listener) { if (listener == null) { throw new IllegalArgumentException("Listener cannot be null"); } // 先尝试从集合移除 boolean removed = listeners.remove(listener); if (removed) { int newCount = listenerCount.decrementAndGet(); // 当计数从1变为0时,断开网络连接 if (newCount == 0) { disconnectNetworkConnection(); } } } // 触发网络事件的方法(示例) public void fireNetworkEvent(NetworkEvent event) { // CopyOnWriteArraySet的迭代器是快照,遍历过程中集合修改不影响遍历 for (NetworkEventListener listener : listeners) { listener.onNetworkEvent(event); } } // 初始化网络连接的逻辑(自定义实现) private void initializeNetworkConnection() { System.out.println("Initializing network connection..."); // 这里写实际的连接代码:比如打开Socket、建立长连接等 } // 断开网络连接的逻辑(自定义实现) private void disconnectNetworkConnection() { System.out.println("Disconnecting network connection..."); // 这里写实际的断开代码:比如关闭Socket、释放资源等 } // 监听器接口定义 public interface NetworkEventListener { void onNetworkEvent(NetworkEvent event); } // 网络事件类定义(示例) public static class NetworkEvent { // 自定义事件属性 } }
方案优势说明
- 适配读多写少场景:
CopyOnWriteArraySet的读操作完全无锁,遍历、查询效率极高,写操作(添加/移除)会复制底层数组,但因为你的场景读远多于写,这种开销完全可以接受。 - 线程安全保障:集合本身是线程安全的,
AtomicInteger的计数操作也是原子性的,不会出现并发下的计数错误或竞态条件。 - 精准触发时机:通过计数的变化(0→1、1→0)精准触发连接/断开逻辑,完全满足你的需求。
- 简洁性:相比用两个Phaser的冗余方案,这个实现逻辑清晰,代码量少,维护成本低。
边界情况处理
- 重复添加监听器:因为用的是
Set,重复添加同一个监听器不会生效,计数也不会重复增加,符合预期。 - 移除不存在的监听器:移除操作会返回
false,计数不会减少,避免误触发断开逻辑。 - 并发添加/移除:原子计数和集合的线程安全特性保证了在高并发场景下,连接/断开逻辑只会被触发一次,不会出现多次初始化或断开的情况。
内容的提问来源于stack exchange,提问作者Gili
相关产品推荐
相关产品推荐

