Java使用Swing同步线程

Java使用Swing同步线程,java,multithreading,swing,Java,Multithreading,Swing,我写了一个程序,它在窗口中显示球,球在移动,在接触时以一定的概率相互吸收 当前版本有效,每次(隐式)调用paintComponent方法时都会计算球的运动: 我的问题是我不知道如何同步球的绘制和运动计算?ColliderPanel甚至需要线程作为成员吗?我刚刚找到了关于如何同步调用同一方法的两个线程的教程,但我想在这里做什么?这看起来像经典的生产者-消费者场景。计算球运动的线程是生产者,绘制球运动的线程是消费者。查看以下主题的教程:或这看起来像经典的生产者-消费者场景。计算球运动的线程是生产者,

我写了一个程序,它在窗口中显示球,球在移动,在接触时以一定的概率相互吸收

当前版本有效,每次(隐式)调用paintComponent方法时都会计算球的运动:


我的问题是我不知道如何同步球的绘制和运动计算?
ColliderPanel
甚至需要线程作为成员吗?我刚刚找到了关于如何同步调用同一方法的两个线程的教程,但我想在这里做什么?

这看起来像经典的生产者-消费者场景。计算球运动的线程是生产者,绘制球运动的线程是消费者。查看以下主题的教程:或

这看起来像经典的生产者-消费者场景。计算球运动的线程是生产者,绘制球运动的线程是消费者。查看以下关于主题的教程:或

使用Swing需要记住的主要一点是,除了Swing事件调度线程(EDT),几乎不应从任何其他线程调用Swing方法

EDT是处于循环中的东西,它等待按键、鼠标单击和其他事件,并在每次程序感兴趣的事件发生时调用处理程序


当您的任何其他线程想要执行会影响GUI的操作时,它应该调用
SwingUtilities.invokeLater(r)
方法,其中
r
是一些
Runnable
对象。invokeLater(r)方法将包含
r
的事件发布到事件队列,EDT将通过调用
r.run()
来处理该事件。然后,r.run()方法可以安全地调用您需要它调用的任何Swing方法。

使用Swing需要记住的一点是,除了Swing事件调度线程(EDT),几乎不应从任何其他线程调用任何Swing方法

EDT是处于循环中的东西,它等待按键、鼠标单击和其他事件,并在每次程序感兴趣的事件发生时调用处理程序


当您的任何其他线程想要执行会影响GUI的操作时,它应该调用
SwingUtilities.invokeLater(r)
方法,其中
r
是一些
Runnable
对象。invokeLater(r)方法将包含
r
的事件发布到事件队列,EDT将通过调用
r.run()
来处理该事件。r.run()方法可以安全地调用您需要它调用的任何Swing方法。

一个建议是将计算移到swingworkers后台处理方法中,并在worker的done方法中调用repaint。

一个建议是将计算移到swingworkers后台处理方法中,并在done中调用repaint工人的方法。

阅读本教程:避免在
paintComponent(Graphics g)
内部调用
repaint()
将计算外包给另一个线程的任何特定原因?Chris K谢谢,我会看看这个@阿文德,为什么我不能那样做?{at}acearch的主要原因是一个教育性的原因,但事先我认为当将来计算变得更复杂时,最好在另一个线程中进行计算。阅读本教程:避免调用
repaint()
inside
paintComponent(图g)
将计算外包给另一个线程有什么特殊原因吗?Chris K谢谢,我来看看这个@阿文德,为什么我不能那样做?{at}acearch的主要原因是一个教育性的原因,但事先我认为,当它在将来变得更复杂时,最好在另一个线程中进行计算。
public class ColliderPanel extends JPanel {
...

@Override
public void paintComponent(Graphics g){
    super.paintComponent(g);

    // calculate balls's movement
    Random r = new Random();
        ListIterator<Ball> it = cp.getColliderPanel().balls.listIterator();
        Vector<Ball> ballsToRemove = new Vector<Ball>();

        while (it.hasNext()) {
            Ball b = it.next();
            b.move(1.0 / 60.0);
            b.collideFrame(cp.getColliderPanel().getSize());

            ListIterator<Ball> it2 = cp.getColliderPanel().balls.listIterator(it.nextIndex());
            while (it2.hasNext()) {
                Ball b2 = it2.next();
                if (b.collide(b2)) {
                    if (r.nextDouble() < 0.5) {
                        if (b.m > b2.m) {
                            b.swallow(b2);
                            ballsToRemove.add(b2);
                        } else {
                            b2.swallow(b);
                            ballsToRemove.add(b);
                        }
                    }
                }
            }
        }

        cp.getColliderPanel().balls.removeAll(ballsToRemove);

        try {
            Thread.sleep((long) (1000.0 / 60.0));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    for(Ball b : balls) b.draw(g);

    repaint();
}

...
}
public class ColliderPanel extends JPanel {
private Thread simThread = new Thread(new SimulateBallsMovement());

@Override
public void paintComponent(Graphics g){
    super.paintComponent(g);

    // calculate balls's movement
    // what to to here? how to synchronize the painting and the calculation?

    for(Ball b : balls) b.draw(g);

    repaint();
}

...
}