简体   繁体   中英

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

I was trying to write a little gravity simulation program. You specify a velocity and angle then it does the math and I used Java2D to draw it real time. The program itself works, I tested it out and it was beautiful. However, I did a little bit of restructuring for clarity purposes and now I'm having an issue.

Here is the intended behavior: The Gravity physics are all defined in its own class. This class basically has a timer that is constantly updating the coordinates taken as parameters. I'm creating this class in the run() (threading) method of another class called Sprite. The invoking class (being Sprite) can retrieve these updated coordinates using the methods I define called getX() and getY() in Gravity. So, once I create the gravity object in Sprite's run() method I have Sprite start an infinite that calls getX & getY methods and updates its own x & y coords.

The issue is, even though the Gravity object and the infinite are on seperate threads, the infinite is freezing the gravity/updating. Why is it doing this?

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

    }
}

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

}

How I initialize Sprite :

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

Your gravity is in the same thread as your sprite.

Your retriev method is called from a key event, which is waiting for the method to be done. Do not use infinite loops for such things.

Gravity should be updated when sprite is updated (x time per second, see updates per second [UPS]). Usualy you will have more then one sprite at once and all of them have to be updated several times per second in a loop.

You should use a seperated thread for ui and events: loot at SwingUtilities.invokeLater()

It would be bette to create a controller class, which stors all the sprite objects and has a update thread, which runs at fixed update rate and call update method of each sprite.


EDIT:

What you have at the moment is:

A Thread, with a object (sprite) inside it, and a object (gravity) as a property of sprite. Now inside of run you just create a new object (g) and then the tread ends up.

If you realy want for each sprite a own gravity thread, you havte to do something like this.

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

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

Using this, on calling Thread.start your sprite method will start to call retrieve.

A Thread allways has a main loop, when you cancle the loop, the tread stops working. In java the run method of Runnable is the start point for your loop, when a thread is ready with the run method, It stops working. So all you want to do inside a new thread, has to be inside the run method.

Set a breakpoint in your method, retrieve() , that contains the infinite loop and run your program in a debugger. You'll see that you call retrieve() from within keyPressed() , which is called by the Swing toolkit on the AWTEventQueue thread. Your infinite loop is on the event dispatch thread and so no more events (including Swing timers) can be processed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM