3

这是我认为不遵循代码应该做什么的代码片段:

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

如果我评论

System.out.println("Hi")

该代码显然不起作用。如果我取消注释它,那么它就是!

注意:当您按下“s”开始游戏时,start 为真。但是,该方法是在开始时调用的,所以“hi”应该显示很多次并且无限期地显示,直到我按下“s”键。

一张图说一千个字,那我给你上百张图(视频)来解释我的意思: https ://dl.dropbox.com/u/2792692/CodeWeird.ogv

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

谁能告诉我发生了什么?

4

2 回答 2

7

看起来布尔值start正在由另一个线程更新,但您没有将其声明为volatile,因此循环永远不会查看更新的值。

通过添加 println 来“修复”它只是 JVM 在获取控制台打印机的本机系统对象时管理线程堆栈状态的方式的一个奇怪结果。解决方法是使 start 不稳定和/或在访问它时同步。

SCCE:

从不打印:

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

在 1 秒后开始向 Hello 发送垃圾邮件,方法是更改​​为:

private volatile boolean start = false;

于 2012-07-19T23:14:59.777 回答
2

我认为 Affe 的想法可能是个好主意,但我想建议你在未来尝试使用Timer而不是 while(true) 循环。至少在我看来要好得多。

于 2012-07-19T23:30:29.547 回答