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

Java弹跳球项目:点击速度调节按钮仅修改后续新建小球速度问题咨询

问题原因分析
  • 核心逻辑错误:原有代码中速度系数change是静态成员变量,所有BallRunnable实例共享该值,修改后所有正在运行的小球线程的Thread.sleep计算都会使用新的系数,直接导致已经运行的小球速度同步变化。
  • 无用的锁逻辑:你添加的Lock完全不符合需求场景,反而会导致多个小球线程抢锁,同一时间只能有一个小球运动,和多线程并发运行的预期相悖。
  • 冗余代码:BallRunnable和BallRunnable2逻辑高度重复,无需单独定义两个类。
  • Swing绘制错误:非EDT线程直接调用paint(getGraphics())会导致绘制异常、闪烁,应该使用repaint()触发Swing的官方绘制调度。
修复方案

只需要修改BallRunnable相关逻辑即可,核心思路是:保留全局静态的默认速度系数,每个小球线程创建时,将当前的全局系数赋值给线程自身的实例成员变量,后续修改全局系数只会影响新创建的线程,已经存在的线程使用自己存储的固定系数,不会被修改。

1. 重构后的BallRunnable类(删除原有的BallRunnable2)

class BallRunnable implements Runnable {
    // 全局默认速度系数,仅作用于后续新建的小球
    private static double globalChange = 1;
    public static final int STEPS = 1000;
    public static final int DELAY = 3;

    // 实例自身的速度系数,创建后固定,不受全局修改影响
    private final double instanceChange;
    private final Ball ball;
    private final JPanel ballPanel;
    // 兼容原BallRunnable2的延迟启动逻辑
    private final boolean delayStart;

    public BallRunnable(Ball aBall, JPanel ballPanel, boolean delayStart) { 
        this.ball = aBall; 
        this.ballPanel = ballPanel;
        this.delayStart = delayStart;
        // 新建实例时保存当前的全局速度系数,后续全局变更不影响该值
        this.instanceChange = globalChange;
    }

    public void run() {
        try {
            if (delayStart) {
                Thread.sleep(100);
            }
            for (int i = 1; i <= STEPS; i++) {
                ball.move(ballPanel.getBounds());
                // 用官方推荐的repaint触发绘制,避免闪烁和线程安全问题
                ballPanel.repaint();
                // 使用实例自身的固定系数计算休眠时间
                Thread.sleep((long)(DELAY * instanceChange));
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }

    // 修改全局速度系数,仅影响后续新建的小球
    public static void speedUp() {
        globalChange = globalChange / 2;
    }

    public static void slowDown() {
        globalChange = globalChange * 2;
    }
}

2. 修改BounceFrame中的小球创建逻辑

public void addBall1() {
    Ball b = new Ball();
    ballPanel.add(b);
    Runnable r = new BallRunnable(b, ballPanel, false);
    new Thread(r).start();
}

public void addBall2() {
    Ball b1 = new Ball();
    Ball b2 = new Ball();
    ballPanel.add(b1);
    ballPanel.add(b2);      
    Runnable r1 = new BallRunnable(b1, ballPanel, false);
    Runnable r2 = new BallRunnable(b2, ballPanel, true);
    new Thread(r1).start();
    new Thread(r2).start();
}

3. 修改速度调整的事件逻辑

class fasterAction extends AbstractAction {
    public fasterAction(String name) { super(name); }
    
    public void actionPerformed(ActionEvent event) {
        BallRunnable.speedUp();
    }
}
class slowerAction extends AbstractAction {
    public slowerAction(String name) { super(name); }
    
    public void actionPerformed(ActionEvent event) {
        BallRunnable.slowDown();
    }
}
验证效果

调整速度后,已经在运动的小球使用创建时保存的固定速度系数,速度不会发生变化,后续新建的小球会使用调整后的速度系数,符合需求。同时删除了无用的锁逻辑,解决了原有多线程阻塞的问题,替换repaint后也解决了绘制闪烁的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 23:24:03