为什么我的无限导致程序的其余部分冻结,即使它在一个单独的线程上?

Why does my infinite cause the rest of the program to freeze even though its on a separate thread?

我正在尝试编写一个重力模拟程序。您指定一个速度和角度,然后它进行数学运算,我使用 Java2D 实时绘制它。该程序本身有效,我对其进行了测试,它很漂亮。但是,为了清楚起见,我做了一些重组,但现在我遇到了问题。

这里是预期的行为:重力物理都是在它自己的 class 中定义的。这个 class 基本上有一个计时器,它不断更新作为参数的坐标。我正在另一个名为 Sprite 的 class 的 运行()(线程)方法中创建此 class。调用 class(作为 Sprite)可以使用我在 Gravity 中定义的称为 getX() 和 getY() 的方法检索这些更新的坐标。因此,一旦我在 Sprite 的 运行() 方法中创建了重力对象,我就让 Sprite 开始无限调用 getX 和 getY 方法并更新它自己的 x 和 y 坐标。

问题是,即使 Gravity 对象和 infinite 在不同的线程上,infinite 正在冻结 gravity/updating。为什么要这样做?

重力Class:

public class Gravity implements ActionListener { // create me in a run() method
                                                    // for a new thread
    final double gravAccel = -32.174;
    double velocity; // in FPS
    double angle; // in degrees
    double x; // centralized location of object in feet
    double y; // centralized location in feet
    double time = 0;
    Timer timer;
    boolean fired = true;
    Point start;

    public Gravity(double x, double y, double velocity, double angle, Point start) {
        this.x = x;
        this.y = y;
        this.velocity = velocity;
        this.angle = angle;
        this.start = start;
        initTimer();
    }



    void initTimer() {
        timer = new Timer(10, this);
        timer.start();
    }   


    public void fire(double velocity, double angle) {
        //timer.start();
        x = (velocity * Math.cos(Math.toRadians(angle))) * time + start.getX();
        y = 0.5 * gravAccel * Math.pow(time, 2) + (velocity * Math.sin(Math.toRadians(angle))) * time + start.getY();
        System.out.println("Time:" + time + "          " + x + "," + y);

    }


    public double getX() {
        return x;
    }
    public double getY() {
        return y;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        time = time + 0.01;
        if (fired == true) {
            fire(velocity, angle);
        }

    }
}

雪碧Class:

public class Sprite implements KeyListener, Runnable {
    public Dimension hitbox;
    double startX = 30;
    double startY = 30;
    double x = startX; // centralized location of object in feet
    double y = startY; // centralized location in feet

    Gravity g;

    public Sprite() {
        hitbox = new Dimension(1, 1);
    }

    @Override
    public void keyPressed(KeyEvent e) {
        // TODO Auto-generated method stub
        int i = e.getKeyCode();
        if (i == KeyEvent.VK_SPACE) {

            retrieve();

        }

    }

    @Override
    public void keyReleased(KeyEvent arg0) {
        // TODO Auto-generated method stub

    }

    @Override
    public void keyTyped(KeyEvent arg0) {
        // TODO Auto-generated method stub

    }

    public void retrieve() {
       for(;;){                                   
        x = g.getX();
        y = g.getY();
      }
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        g = new Gravity(x, y, 50, 70, new Point((int) startX, (int) startY));
    }

}

我如何初始化 Sprite:

Sprite s = new Sprite();
Thread t = new Thread(s);
t.start();

在您的方法 retrieve() 中设置一个断点,其中包含无限循环和 运行 您在调试器中的程序。您会看到您从 keyPressed() 中调用了 retrieve(),这是由 Swing 工具包在 AWTEventQueue 线程上调用的。您的无限循环在事件调度线程上,因此无法处理更多事件(包括 Swing 计时器)。

你的重力和你的精灵在同一个线程中。

您的检索方法是从一个键事件调用的,该事件正在等待该方法完成。不要对这样的事情使用无限循环。

重力应该在精灵更新时更新(每秒 x 次,参见每秒更新 [UPS])。通常你一次会有不止一个精灵,所有的精灵都必须在一个循环中每秒更新几次。

您应该为 ui 和事件使用单独的线程: 在 SwingUtilities.invokeLater()

抢劫

最好创建一个控制器class,它存储所有精灵对象并有一个更新线程,运行以固定的更新速率运行并调用每个精灵的更新方法。


编辑:

您目前拥有的是:

一个线程,里面有一个对象(精灵),一个对象(重力)作为精灵的属性。现在在 运行 中,您只需创建一个新对象 (g),然后胎面就结束了。

如果你真的想让每个精灵都有自己的重力线,你必须这样做。

public Sprite(){
  //do what you want to
  g = new Gravity(...);
}

public void run(){
  while(true){
    retrieve();
  }
}

使用此方法,在调用 Thread.start 时您的 sprite 方法将开始调用 retrieve。

线程总是有一个主循环,当你取消循环时,线程停止工作。在 java 中,Runnable 的 运行 方法是循环的起点,当线程准备好使用 运行 方法时,它将停止工作。所以你想在新线程中做的所有事情都必须在 运行 方法中。