Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/343.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 循环未终止时计时_Java_Timer_While Loop_Timertask - Fatal编程技术网

Java 循环未终止时计时

Java 循环未终止时计时,java,timer,while-loop,timertask,Java,Timer,While Loop,Timertask,运行此代码时,我希望它将测试变量递增5秒,然后完成 import java.util.Timer; import java.util.TimerTask; public class Test { private static boolean running; public static void main( String[] args ) { long time = 5 * 1000; // converts time to millisecond

运行此代码时,我希望它将测试变量递增5秒,然后完成

import java.util.Timer;
import java.util.TimerTask;

public class Test {
    private static boolean running;

    public static void main( String[] args ) {
        long time = 5 * 1000;       // converts time to milliseconds
        long test = Long.MIN_VALUE;
        running = true;

        // Uses an anonymous class to set the running variable to false
        Timer timer = new Timer(); 
        timer.schedule( new TimerTask() { 
            @Override
            public void run() { running = false; }
        }, time );

        while( running ) {
            test++;
        }

        timer.cancel();
        System.out.println( test );
    }
}
然而,当我运行它时,程序并没有结束(我假设,我已经给了它一段合理的时间)。但是,如果我将while循环更改为

    while( running ) {
        System.out.println();
        test++;
    }
程序在预期的时间内完成(并打印出许多行)。我不明白。为什么会发生这种行为?

根据我们的说法,无法保证非易失性字段何时会从另一个线程中可见。在您的例子中,您的主要方法是JIT编译的,JIT编译器合理地假设,由于当前线程没有修改循环中运行的
变量,因此我们不应该在每次迭代时读取它,并将循环转换为无限循环。关于这件事,甚至没有任何证据


添加
System.out.println
调用时,JIT编译器似乎无法将其内联,因此无法确保此方法不会修改运行的
变量,从而关闭字段读取优化。然而,这不应被视为问题的解决方案:即使您的内部有
System.out.println
,Java的新版本可能会更智能并优化您的循环。

让我们更深入地了解您的代码

如果你调试你的代码,它会工作。这是因为您将只看到一个线程,而没有缓存。Java可以使用基于线程的缓存机制。您需要将其读写到主内存中

因此,如果您在运行的变量上使用
volatile
关键字,jvm会将其视为可由多个线程编辑,并且不应该缓存它


因此,在您的情况下,解决方案是将
volatile
添加到您的运行变量。

您正在更新
运行
变量,该变量位于与
main
方法不同的线程中。Java内存模型不保证在不同线程中看到非易失性变量的更新

最简单的解决方案是将变量
设置为volatile
:这会在线程访问变量时强制检查变量的“当前”值

其他解决方案包括使用
AtomicBoolean
而不是
boolean
,以及将对
运行
的访问包装在相互
同步的
块中(即,访问
运行
的代码与更新它的代码在同一监视器上同步)


我强烈建议您在实践中选择Java并发的一个副本,它详细描述了这个问题。

如果让运行
变得不稳定会怎么样?
?我刚刚使用JDK 7和IntelliJ 11测试了您的代码,两个版本都在几秒钟内完成。你用什么来跑?@AndyTurner哇,我以前从未遇到过volatile关键字。这使得代码能够工作。谢谢@TimBiegeleisen Java 8 update 45I接受了这个答案,因为它链接了其他信息。谢谢