3

Here is a snippet of the code I think does not follow what code should do:

public void updateTimeElapsed() {
    timeElapsedLabel.setText("Time elapsed: " + ((System.nanoTime() - time) / Math.pow(10, 9)));
}

public void updateTimeElapsedIndefinitely() {
    while (true) {
        //System.out.println("Hi");
        //TODO: Why this no work?
        if (start) { System.out.println("Shoulda'"); updateTimeElapsed(); }
    }
}

If I comment

System.out.println("Hi")

The code apparently does not work. If I uncomment it, then it does!

Note: start is true as soon as you press 's' to start the game. However, the method is called in the beginning so "hi" should be displayed many times and indefinitely until I press the 's' key.

A picture says a thousand words, so I'll give you hundreds of pictures (video) to explain what I mean: https://dl.dropbox.com/u/2792692/CodeWeird.ogv

https://dl.dropbox.com/u/2792692/CodeWeird.wmv

Can anyone tell me what is going on?

Supervisor
  • 582
  • 1
  • 6
  • 20
  • 2
    Your loop may be too tight. It's notable that 'Hi' starts printing before it gets to the point where 'Shoulda' prints, and it's printing rapidly. How are you invoking this method? If you let it run a long time, does something eventually display? You might need to insert a Thread.sleep() in there. – Nathaniel Ford Jul 19 '12 at 23:03
  • I'll add a little bit of explanation: start is true as soon as you press 's' to start the game. However, the method is called in the beginning so "hi" should be displayed many times and indefinitely until I press the 's' key. What do you mean by "too tight"? – Supervisor Jul 19 '12 at 23:11
  • Declaring "start" as `volatile` as @Affe says should fix your problem, but I would *also* put a very brief `Thread.sleep()` inside the `while (true)` because spinning in a tight do-nothing busy-loop like that can really screw with system responsiveness. – Stephen P Jul 19 '12 at 23:27

2 Answers2

7

Looks like the boolean start is being updated by another thread but you didn't declare it as volatile, so the loop never looks at the updated value.

"Fixing" it by adding the println is just a wierd consequence of the way JVM manages the thread's stack state when it goes to acquire the native system object for the console printer. The fix is to make start volatile and/or synchronize around accessing it.

SCCE:

Never prints:

public class Testit {

    public static void main(String[] args) {
        busted t = new busted();
        t.start();
        try {
        Thread.sleep(1000L);
        } catch (Exception e) {}
        t.startUpdating();

}

    public static class busted extends Thread {

        private boolean start = false;

        public void startUpdating() {
            start = true;
        }

        @Override
        public void run() {
            updateTimeElapsedIndefinitely();
        }

        public void updateTimeElapsedIndefinitely() {
            while (true) {
                if (start) {
                    System.out.println("Hello");
                }
            }
        }
    }
}

Starts spamming Hello after 1 second by changing to this:

private volatile boolean start = false;

Affe
  • 47,174
  • 11
  • 83
  • 83
2

I think Affe idea myght be the good one, but I wanna suggest you to try to use Timer in the future instead of while(true) loop. It is much better in my opinion at least.

Doua Beri
  • 10,612
  • 18
  • 89
  • 138
  • Yeah, Affe's explanation was great. As for Timer - this is just the beginning of the "game". I'm making sure I don't forget Java as I learn other languages. :P – Supervisor Jul 19 '12 at 23:35