Swing应用中的数据更新节流技术

Swing应用中的数据更新节流技术

在开发Swing应用时,我们经常会遇到需要频繁更新数据的场景,比如实时金融数据展示。如果数据更新的频率过高,可能会导致界面冻结,这是因为大量的重绘事件(painting events)连续触发,导致事件分发线程(EDT)长时间被阻塞。为了避免这种情况,我们可以使用节流(Throttling)技术来控制数据接收的速率。本文将通过一个具体实例,展示如何在Swing应用中实现节流,并应用到JTable数据更新中。

节流器的实现

首先,我们定义一个通用的节流器类Throttler,用于控制数据更新的频率。这个类使用了Timer来定时触发更新事件,并确保这些事件在EDT中执行。

public class Throttler {
    private Timer timer;

    public Throttler(int rate, Runnable updater) {
        timer = new Timer(rate, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                timer.stop();
                updater.run();
            }
        });
    }

    public void updateReceived() {
        if (!SwingUtilities.isEventDispatchThread()) {
            throw new IllegalArgumentException("updateReceived() must be called in EDT");
        }
        if (!timer.isRunning()) {
            timer.restart();
        }
    }
}

高频数据服务

接下来,我们创建一个模拟高频数据更新的服务TestDataService。这个服务会模拟实时金融数据的更新,并通过BiConsumer接口将更新传递给监听器。

public enum TestDataService {
    Instance;
    private String[] currencyPairs = {"EUR/USD", "USD/JPY", "GBP/USD", "USD/CHF", "USD/CAD", "AUD/USD", "NZD/USD", "EUR/GBP", "EUR/AUD", "GBP/JPY", "CHF/JPY", "NZD/JPY", "GBP/CAD"};
    public void listenToDataUpdate(BiConsumer<String, BigDecimal> forexListener) {
        ExecutorService es = Executors.newSingleThreadExecutor();
        es.execute(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    int i = ThreadLocalRandom.current().nextInt(0, currencyPairs.length);
                    BigDecimal rate = BigDecimal.valueOf(Math.random() * 10);
                    rate = rate.setScale(2, RoundingMode.CEILING);
                    forexListener.accept(currencyPairs[i], rate);
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
    }
}

JTable数据模型

我们使用AbstractTableModel来创建一个ForexTableModel类,用于管理JTable的数据。

public class ForexTableModel extends AbstractTableModel {
    private Map<String, BigDecimal> forexRates = new TreeMap<>();
    private String[] columnNames = {"Currency Pair", "Rate"};

    public void updateRateWithoutFiringEvent(String currency, BigDecimal rate) {
        forexRates.put(currency, rate);
    }

    @Override
    public String getColumnName(int column) {
        return columnNames[column];
    }

    @Override
    public int getRowCount() {
        return forexRates.size();
    }

    @Override
    public int getColumnCount() {
        return columnNames.length;
    }

    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        if (columnIndex == 0) {
            String currency = getCurrencyByRow(rowIndex);
            return currency;
        } else if (columnIndex == 1) {
            String currency = getCurrencyByRow(rowIndex);
            return forexRates.get(currency);
        }
        return null;
    }

    private String getCurrencyByRow(int rowIndex) {
        return forexRates.keySet().toArray(new String[forexRates.size()])[rowIndex];
    }
}

主类与节流应用

最后,我们在主类ThrottlingExampleMain中应用节流技术,以避免在大量数据更新时界面冻结的问题。

public class ThrottlingExampleMain {
    public static void main(String[] args) {
        ForexTableModel tableModel = new ForexTableModel();
        JTable table = new JTable(tableModel);
        listenToForexChanges(tableModel);
        JFrame frame = createFrame();
        frame.add(new JScrollPane(table));
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    private static void listenToForexChanges(ForexTableModel tableModel) {
        Throttler throttler = new Throttler(1000, new Runnable() {
            @Override
            public void run() {
                tableModel.fireTableDataChanged();
            }
        });
        TestDataService.Instance.listenToDataUpdate(
            (pair, rate) -> SwingUtilities.invokeLater(() -> {
                tableModel.updateRateWithoutFiringEvent(pair, rate);
                throttler.updateReceived();
            }));
    }

    private static JFrame createFrame() {
        JFrame frame = new JFrame("Throttling Example");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(new Dimension(500, 300));
        return frame;
    }
}

通过上述代码,我们可以看到,在启用节流的情况下,即使数据更新频率很高,界面也不会冻结。相反,如果没有使用节流技术,界面在大量数据更新时会出现明显的卡顿现象。

总结

节流技术是处理Swing应用中高频数据更新的有效手段。通过控制数据更新的速率,我们可以避免界面冻结,提升用户体验。本文通过一个具体的实例,展示了如何在Swing应用中实现节流,并应用到JTable数据更新中。希望这能帮助你在开发中遇到类似问题时,能够快速找到解决方案。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值