You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现首监听器添加连网、末监听器移除断网的线程安全集合?

解决方案:结合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 {
        // 自定义事件属性
    }
}

方案优势说明

  1. 适配读多写少场景:CopyOnWriteArraySet的读操作完全无锁,遍历、查询效率极高,写操作(添加/移除)会复制底层数组,但因为你的场景读远多于写,这种开销完全可以接受。
  2. 线程安全保障:集合本身是线程安全的,AtomicInteger的计数操作也是原子性的,不会出现并发下的计数错误或竞态条件。
  3. 精准触发时机:通过计数的变化(0→1、1→0)精准触发连接/断开逻辑,完全满足你的需求。
  4. 简洁性:相比用两个Phaser的冗余方案,这个实现逻辑清晰,代码量少,维护成本低。

边界情况处理

  • 重复添加监听器:因为用的是Set,重复添加同一个监听器不会生效,计数也不会重复增加,符合预期。
  • 移除不存在的监听器:移除操作会返回false,计数不会减少,避免误触发断开逻辑。
  • 并发添加/移除:原子计数和集合的线程安全特性保证了在高并发场景下,连接/断开逻辑只会被触发一次,不会出现多次初始化或断开的情况。

内容的提问来源于stack exchange,提问作者Gili

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:17:10