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

Java Timer.scheduleAtFixedRate运行时无法修改周期求助

问题根源分析

你遇到的问题很典型:Timer.scheduleAtFixedRate() 调用时会一次性读取当时的intperiod值并固定下来,后续修改intperiod变量根本不会影响已经在运行的Timer任务周期——就像你定了一个闹钟,之后改了设定的间隔,闹钟不会自动跟着变,得重新设置才行。

另外还有个小隐患:你在后台TimerTask里直接调用repain()(应该是repaint()?你代码里打错了)和更新Swing组件(比如jLabel6.setText()),这是不安全的,因为Swing组件必须在**事件调度线程(EDT)**里操作,后台线程直接修改可能导致界面卡顿或异常。


推荐解决方案:改用Swing Timer

对于Swing应用,官方更推荐使用javax.swing.Timer,它天生适配EDT,而且支持动态修改延迟时间,完美解决你的滑块调节周期需求。下面是修改后的关键代码:

首先,替换Timer类型并初始化:

import javax.swing.Timer; // 注意导入这个Timer,不是java.util.Timer

public class GameOfLife extends javax.swing.JFrame {
    int intperiod = 100;
    int wid = 50, hei = 50;
    boolean[][] currentMove = new boolean[hei][wid], nextMove = new boolean[hei][wid];
    boolean play;
    public static int intpopulation = 0;
    Image offScrImg;
    Graphics offScrGraph;
    public static int intGeneration = 0;
    Timer swingTimer; // 换成Swing Timer

    public GameOfLife() {
        initComponents();
        offScrImg = createImage(jPanel2.getWidth(), jPanel2.getHeight());
        offScrGraph = offScrImg.getGraphics();

        // 初始化Swing Timer
        swingTimer = new Timer(intperiod, e -> {
            if (play) {
                intGeneration++;
                // 确保在EDT线程更新界面组件
                SwingUtilities.invokeLater(() -> {
                    jLabel6.setText("Generation: " + intGeneration);
                });

                // 计算下一代状态
                for (int i = 0; i < hei; i++) {
                    for (int j = 0; j < wid; j++) {
                        nextMove[i][j] = decide(i, j);
                    }
                }
                // 同步当前状态
                System.arraycopy(nextMove, 0, currentMove, 0, hei);
                // 在EDT线程重绘界面
                SwingUtilities.invokeLater(this::repain);
            }
        });
        swingTimer.start(); // 启动Timer
        repain();
    }

然后修改滑块的事件处理方法,直接更新Timer延迟:

private void jSlider1StateChanged(javax.swing.event.ChangeEvent evt) {
    int newPeriod = jSlider1.getValue();
    jLabel4.setText(newPeriod + " milliseconds"); // 修正拼写错误:milisecounds → milliseconds
    intperiod = newPeriod;
    // 直接修改Swing Timer的延迟,立即生效
    swingTimer.setDelay(newPeriod);
}

如果你坚持用java.util.Timer的解决方案

如果你不想换Timer类型,那每次滑块变化时,需要取消原来的TimerTask,重新创建并调度新任务:

首先,把TimerTask设为成员变量方便管理:

public class GameOfLife extends javax.swing.JFrame {
    // ... 其他变量
    Timer time = new Timer();
    TimerTask currentTask; // 新增成员变量存储当前任务

然后抽离Timer任务的创建逻辑:

public GameOfLife() {
    initComponents();
    // ... 其他初始化代码
    startOrUpdateTimer(); // 调用初始化方法
    repain();
}

// 新增方法:启动或更新Timer任务
private void startOrUpdateTimer() {
    // 如果已有任务,先取消
    if (currentTask != null) {
        currentTask.cancel();
    }
    // 创建新任务
    currentTask = new TimerTask() {
        public void run() {
            if (play == true) {
                intGeneration++;
                // 必须用SwingUtilities.invokeLater更新Swing组件
                SwingUtilities.invokeLater(() -> {
                    jLabel6.setText("Generation: " + intGeneration);
                });
                // 计算下一代状态
                for (int i = 0; i < hei; i++) {
                    for (int j = 0; j < wid; j++) {
                        nextMove[i][j] = decide(i, j);
                    }
                }
                System.arraycopy(nextMove, 0, currentMove, 0, hei);
                // 在EDT线程重绘
                SwingUtilities.invokeLater(() -> repain());
            }
        }
    };
    // 重新调度任务
    time.scheduleAtFixedRate(currentTask, 0, intperiod);
}

最后修改滑块事件触发更新:

private void jSlider1StateChanged(javax.swing.event.ChangeEvent evt) {
    int newPeriod = jSlider1.getValue();
    jLabel4.setText(newPeriod + " milliseconds");
    intperiod = newPeriod;
    // 更新Timer任务
    startOrUpdateTimer();
}

额外小提示
  1. 你代码里的repain()是拼写错误,要改成repaint()。
  2. decide()方法里更新jLabel5.setText()的逻辑也要放到SwingUtilities.invokeLater()里,避免线程安全问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:38:01