2011-07-12 101 views
4

使用一个基本示例来说明我的问题我有两个近乎相同的代码位。While循环和线程的无限循环问题

此代码会导致while循环无限运行。

private boolean loadAsset() { 
    new Thread(new Runnable() { 

     @Override 
     public void run() { 

      // Do something 
      loaded = true; 

     } 
    }).start(); 

    while (!loaded) { 
     // System.out.println("Not Loaded"); 
    } 
    System.out.println("Loaded"); 
    return false; 
} 

此代码然而(即做在while循环的东西)导致要成功评价了loaded变量并允许while环打破和方法来完成。

private boolean loadAsset() { 
    new Thread(new Runnable() { 

     @Override 
     public void run() { 

      // Do something 
      loaded = true; 

     } 
    }).start(); 

    while (!loaded) { 
     System.out.println("Not Loaded"); 
    } 
    System.out.println("Loaded"); 
    return false; 
} 

任何人都可以向我解释为什么这是?

+0

你为什么要依靠一个可以被其他领域改变的领域价值?你可能不得不让整个块同步 – Reddy

+2

是'加载''volatile'吗? – axtavt

回答

6

检查'loaded'是否被明确声明为volatile。

说明:如果一个变量被多个线程读取和/或写入,那么您需要采取适当的线程安全措施。一种这样的线程安全措施是易失性的,它适用于原始值(或对象引用),它们被读取或写为'简单'动作,其中在给定时刻写入的值不取决于先前读取的值。有关更多信息,我的网站上有关于volatile的文章(以及有关线程安全性的其他信息)可能有所帮助。

+0

对,但没有解释?嗯...好吧。 :) – mre

+0

对不起,添加了一个解释。 –

2

请阅读Memory Consistency Errors。基本上,不同的线程对于什么应该是相同的数据有不一致的看法。为了解决这个问题,请阅读Synchronization。或者仅仅声明loadedvolatile,因为它的值只能由单个线程写入。

6

只有第一个循环“出现”才能无限运行。实际上,您正在运行“主动等待”,并将100%的CPU烧毁,以便您的OS或JVM无法进行上下文切换并让其他线程运行。

另一方面,与System.out.println()相关的是I/O,导致有些“非活动等待”。 OS或JVM可以切换上下文,并启动另一个线程。

如果你运行你的第一个程序10个小时,我敢肯定,循环会破坏最终

4

如果loaded不挥发,在JIT是免费的通过将其放置在寄存器中,而不是优化它每次从内存加载它。在第二种情况下,循环对于JIT来说太复杂以至于不需要每次都加载loaded

注意:它是JIT而不是javac编译器,它优化了代码。

+1

不错。我没有意识到... –

0

我相信你正在经历一个空循环的Busy Wait,它永远不会睡觉。因此,你的线程设置为true将永不运行。