Java中的奇怪行为,在多线程程序中具有非同步访问

Java中的奇怪行为,在多线程程序中具有非同步访问,java,concurrency,Java,Concurrency,我更改了一个值,该值用于确定while循环何时在单独的线程中终止 我不想知道如何让它工作。如果我仅通过同步的getter/setter访问变量测试,它将按预期工作 我本以为,如果一些读/写命令由于并发性而丢失,程序有时不会终止,但永远不会终止。这就是使我困惑的地方 我想知道为什么没有打印命令,程序永远不会终止。我想了解为什么print命令会改变任何东西 public class CustomComboBoxDemo { public static bool

我更改了一个值,该值用于确定while循环何时在单独的线程中终止
我不想知道如何让它工作。如果我仅通过同步的getter/setter访问变量测试,它将按预期工作

我本以为,如果一些读/写命令由于并发性而丢失,程序有时不会终止,但永远不会终止。这就是使我困惑的地方
我想知道为什么没有打印命令,程序永远不会终止。我想了解为什么print命令会改变任何东西

     

    public class CustomComboBoxDemo  {
        public static boolean test = true;
        public static void main(String[] args) {
            Thread user =new Thread(){
                @Override
                public void run(){
                    try {
                        sleep(2000);
                    } catch (InterruptedException e) {}
                    test=false;
                }
            };
            user.start();
            while(test) {
                System.out.println("foo"); //Without this line the program does not terminate..
            }
        }
    }


我想这与处理IO的方式有关。如果没有打印,您可能会看到java应用程序使用所有可用的CPU时间;对于打印,IO延迟可能会为其他处理留出足够的CPU时间

测试该理论的一种快速方法是将printlns放在线程的run()方法中,以查看该线程是否实际执行过。根据我的经验,无限的空循环会导致许多奇怪的行为


这就是说,在JDK 1.6.0_10_b23下的工作站上,它似乎可以很好地终止如果
test
变量未定义为,编译器可能会将不包含任何操作的循环优化为
而(true)
主线程的循环,并且程序永远不会结束


否则,实际上会检查
test
变量的值,当第二个线程更改其值时,主线程离开
while
循环,程序终止。

最可能的解释是,变量只读取一次,将
while
变成无限循环(或无操作). 由于您没有将
test
声明为
volatile
,因此允许编译器执行此类优化


一旦您从循环中调用外部函数,编译器就无法再证明
test
在循环迭代中保持不变,也无法执行优化。

似乎您的循环被错误地编译为繁忙等待。向布尔值中添加volatile关键字可更正“问题”。

publicstaticbooleantest=true;
public static boolean test = true;
public static void main(String[] args) {
    Thread user =new Thread(){
        @Override
        public void run(){
            try {
                sleep(2000);
            } catch (InterruptedException e) {}
            test=false;
            System.out.println("Thread.end <"+test+">");
        }
    };
    user.start();
    while(test);
}
公共静态void main(字符串[]args){ 线程用户=新线程(){ @凌驾 公开募捐{ 试一试{ 睡眠(2000年); }捕获(中断异常e){} 测试=假; System.out.println(“Thread.end”); } }; user.start(); while(测试); }
那很有趣。编译器很可能会在无止境的循环中对此进行优化,而不是在每个循环中读取值

将测试定义为修复此问题,并让您的程序终止


顺便说一句:您可能已经知道应该使用user.join()来等待线程结束

我不明白您试图通过使用已知未正确同步的代码来做什么


正如一些人所报告的,在他们的机器上,代码的行为与在您的机器上不同。同步不良代码的行为是未定义的。试图理解它的功能是没有意义的,因为这种行为会随着JVM版本或体系结构的变化而改变。

同意mcfinnigan的观点。向线程添加一些调试打印。当某些东西不能按预期工作时,总是要做一些工作来证明你的假设是正确的,在这种情况下,单独的线程是按设计工作的。我想知道,是字节码编译器还是JIT编译器进行了这种优化?@Max:在我的系统上字节码编译器没有这样做,所以它必须是JIT编译器。顺便说一句,也可能是它不断地读取数据,但这样做是从一个高速缓存(如CPU寄存器)进行的,而这个高速缓存不会影响对主内存的写入。将字段标记为
volatile
也可以解决此问题。顺便说一句,窃取答案做得不错;-)@瓦金沙尔:别傻了。看: