后台线程不起作用,但使用简单的'System.out'工作

时间:2015-12-11 10:57:29

标签: java multithreading

一个奇怪的事情。下面的代码有效,如果条件desiredHealth < p.getFakeHealth()为真,它就有可能。

     @Override
     public void run(){
        while(game_running){
            System.out.println("asd");
            if(desiredHealth < player.getFakeHealth()){
             DOES SOMETHING
          }
        }

但是......没有'System.out'它不起作用。它不检查条件。 它在某种程度上是低优先级,或者其他什么。

     @Override
     public void run(){
        while(game_running){
            if(desiredHealth < player.getFakeHealth())
             DOES SOMETHING
          }
        }

我是线程的新手,所以请不要对我大喊:)

仅仅是为了获取信息,这个线程是一个普通的类,它“扩展了线程”,是的 - 它正在运行。 “game_running”也一直都是真的。

3 个答案:

答案 0 :(得分:4)

变量必须是volatile,因为volatile关键字表示值可能会在不同的访问之间发生变化,即使它似乎没有被修改。

因此,请确保game_running已声明为volatile

答案 1 :(得分:1)

<强>说明: 啊,我在一个较老的SO问题上看过这个。我会尝试找到它以获取更多信息。

您的问题正在发生,因为输出流的print正在阻塞当前线程,desiredHealthplayer.getFakeHealth()表达式之一获得第二次机会被其他线程评估/更改voilà !魔术发生了。这是因为printf上的glibc已同步,因此在您打印时,其余操作正在等待println操作完成。

解决: 我们没有足够的上下文(谁正在初始化播放器,谁进行更改等等),但很明显你有一个线程问题,某些东西没有正确同步,你的后台线程使用坏值。其中一个原因可能是某些变量不是volatile,如果后台线程读取缓存值,则表明您已经遇到问题。

答案 2 :(得分:1)

关于并发性需要研究的一个主题是Java memory model(这是官方规范,但我建议你阅读一本教程或一本好书,因为规范对于初学者来说相当复杂)

当不同的线程使用相同的内存时(使用相同的变量 - 例如当一个人写入变量,另一个根据他们的值做出决策时)的一个问题是出于优化原因,一个人写的值另一方并不总是看到线程。

例如,一个线程可以在一个CPU上运行,并且该变量被加载到该CPU中的寄存器中。如果需要一直将其写回主存储器,则会降低处理速度。因此它在该寄存器中操作它,并且只在必要时才将其写回内存。但是如果另一个线程期望看到第一个线程正在编写的值呢?

在这种情况下,在它们被回写之前它不会看到它们,这可能永远不会发生。

有几种方法可以确保写入操作被“提交”#34;在另一个线程需要使用它们之前的内存。一种是使用同步,另一种是使用volatile关键字。

System.out.println()实际上包含一个同步操作,因此它可能会导致这些变量被提交到内存,从而使线程能够看到更新后的值。

将变量声明为volatile意味着所有其他线程立即看到其中的任何更改。因此,使用volatile变量也是确保看到它们的一种方式。

用于决定是否保持线程运行的变量通常应该声明为volatile。但是,在您的情况下,变量desiredHealth(如果它由不同的线程编写)和任何变量getFakeHealth()依赖(如果它们由不同的线程编写)应该是易变的或以其他方式同步。

最重要的是,无论两个线程之间共享的信息需要同步还是至少使用volatile。可以不分享未共享的信息。