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

时间:2016-01-18 18:41:07

标签: java multithreading infinite-loop

我正在尝试编写一个小重力模拟程序。你指定一个速度和角度,然后它做数学,我用Java2D实时绘制它。程序本身有效,我测试了它,它很漂亮。但是,出于清晰的目的,我做了一些重组,现在我遇到了问题。

这是预期的行为:重力物理都是在自己的类中定义的。这个类基本上有一个定时器,它不断更新作为参数的坐标。我在另一个名为Sprite的类的run()(线程)方法中创建了这个类。调用类(是Sprite)可以使用我在Gravity中定义的名为getX()和getY()的方法来检索这些更新的坐标。所以,一旦我在Sprite的run()方法中创建了引力对象,我就会让Sprite启动一个无限的调用getX& getY方法并更新自己的x& y coords。

问题是,即使Gravity对象和无限对象在单独的线程上,无限正在冻结重力/更新。它为什么这样做?

重力等级:

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);
        }

    }
}

精灵类:

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 s = new Sprite();
Thread t = new Thread(s);
t.start();

2 个答案:

答案 0 :(得分:1)

你的引力与你的精灵在同一个线程中。

从一个键事件调用您的retrievev方法,该事件正在等待方法完成。不要使用无限循环来做这些事情。

更新精灵时应更新重力(每秒x次,请参阅每秒更新次数[UPS])。通常,您将同时拥有多个精灵,并且所有精灵都必须每秒更新几次。

你应该为ui和事件使用一个单独的线程: 抢劫SwingUtilities.invokeLater()

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

修改

目前你所拥有的是:

一个线程,其中包含一个对象(精灵),一个对象(重力)作为精灵的属性。现在在运行中你只需创建一个新对象(g),然后踏板就会结束。

如果你真的希望每个精灵都有一个自己的重力线程,那么你就可以做这样的事情了。

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

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

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

线程总是有一个主循环,当你循环时,踏板停止工作。在java中,Runnable的run方法是循环的起点,当一个线程准备好run方法时,它停止工作。所以你想在新线程中做的只是在run方法中。

答案 1 :(得分:0)

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