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

Java中如何高效检测静态集合变量变化?避免轮询高CPU占用

优化方案:用事件通知替代轮询避免CPU占用过高

你的核心问题是忙等待(Busy Waiting):主线程的for循环没有任何休眠或阻塞,会持续占用CPU核心资源,导致风扇高速运转。既然positions的更新是由WebSocket事件(示例中为后台线程)触发的,最佳方案是采用观察者模式,在集合更新时主动通知监听逻辑,彻底消除轮询。

具体优化步骤

1. 定义位置变化监听接口

创建一个接口,用于定义集合更新时的回调逻辑:

public interface PositionChangeListener {
    void onPositionChanged(Set<String> positions);
}

2. 重构Exchange接口

移除接口中的静态可变集合(接口不应持有可变状态),改为提供监听注册和集合访问方法:

import java.util.Set;

public interface Exchange {
    void subscribePositions();
    void addPositionChangeListener(PositionChangeListener listener);
    Set<String> getPositions();
}

3. 修改ExchangeImpl实现类

将集合状态移到实现类中,在更新集合时主动通知所有注册的监听者:

import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.ConcurrentHashMap;

public class ExchangeImpl implements Exchange {
    // 线程安全的集合存储位置数据
    private final Set<String> positions = ConcurrentHashMap.newKeySet();
    // 线程安全的监听者集合,避免并发修改问题
    private final Set<PositionChangeListener> listeners = new CopyOnWriteArraySet<>();

    @Override
    public void subscribePositions() {
        Thread thread = new Thread(() -> {
            while (!Thread.currentThread().isInterrupted()) {
                int delay = (int) (Math.random() * 1000);
                try {
                    Thread.sleep(delay);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    Thread.currentThread().interrupt();
                    return;
                }

                boolean isChanged = false;
                if (Math.random() > 0.99) {
                    positions.add(Math.random() + "");
                    isChanged = true;
                }

                if (positions.size() > 3) {
                    positions.clear();
                    isChanged = true;
                    break;
                }

                // 只有集合变化时才通知监听者
                if (isChanged) {
                    notifyPositionChange();
                }
                System.out.println(positions);
            }
        });
        thread.start();
    }

    @Override
    public void addPositionChangeListener(PositionChangeListener listener) {
        listeners.add(listener);
    }

    @Override
    public Set<String> getPositions() {
        return positions;
    }

    // 通知所有监听者集合变化
    private void notifyPositionChange() {
        for (PositionChangeListener listener : listeners) {
            listener.onPositionChanged(positions);
        }
    }
}

4. 修改Main类,使用监听替代轮询

注册监听者,在集合变化时执行业务逻辑,不再需要轮询:

import java.util.Set;

public class Main {
    public static void main(String[] args) {
        Exchange exchange = new ExchangeImpl();
        int[] totalTrades = {0}; // 用数组捕获局部变量,适配lambda的不可变要求

        // 注册位置变化回调
        exchange.addPositionChangeListener(positions -> {
            int currentSize = positions.size();
            if (currentSize > totalTrades[0]) {
                // 这里执行你的业务逻辑
                System.out.println("位置数量更新:" + currentSize);
                totalTrades[0] = currentSize;
            }
            // 当集合清空时退出程序
            if (currentSize == 0) {
                System.out.println("Got out of loop");
                System.exit(0);
            }
        });

        exchange.subscribePositions();
        // 初始添加元素触发第一次通知
        exchange.getPositions().add("abc");
    }
}

关键优化点说明

  • 消除忙等待:主线程不再持续轮询,仅在集合实际变化时执行逻辑,CPU占用率会大幅降低。
  • 线程安全:使用ConcurrentHashMap.newKeySet()保证集合操作的线程安全,CopyOnWriteArraySet避免监听者集合的并发修改异常。
  • 合理的状态管理:将可变集合从接口移到实现类,符合面向接口设计的原则,避免接口持有可变状态的不良实践。
  • 优雅的终止逻辑:后台线程处理中断信号,避免资源泄漏;集合清空时主动退出程序。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 10:17:13