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
相关产品推荐
相关产品推荐

