繁体   English   中英

后台线程不起作用,但是使用简单的“ System.out”即可

[英]Background Thread doesn't work, but with a simple 'System.out' works

一件奇怪的事。 下面的代码有效,如果条件desiredHealth < p.getFakeHealth()为true,则可以完成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”一直都是真实的。

该变量必须是volatile变量,因为volatile关键字指示一个值可能会在不同的访问之间改变,即使该值看起来没有被修改。

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

说明:啊,我已经在一个较旧的SO问题上看到了这一点。 我将尝试查找它以获取更多信息。

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

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

您需要研究的有关并发性的主题之一是Java内存模型 (这是官方规范,但我建议您阅读教程或一本好书,因为该规范对于初学者而言相当复杂。

当不同的线程使用相同的内存(使用相同的变量-例如,当一个线程正在写入变量,另一个线程根据其值进行决策)时,问题之一是出于优化原因,一个线程写入的值不是总是被对方看到。

例如,一个线程可以在一个CPU上运行,然后将该变量加载到该CPU的寄存器中。 如果需要一直将其写回到主存储器,则会减慢处理速度。 因此,它将在该寄存器中对其进行操作,并且仅在必要时才将其写回到内存中。 但是,如果另一个线程期望看到第一个线程正在写入的值怎么办?

在这种情况下,直到将它们写回后才能看到它们,这可能永远不会发生。

有几种方法可以确保在另一个线程需要使用写操作之前将写操作“提交”到内存。 一种是使用同步,另一种是使用volatile关键字。

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

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

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

最重要的是,两个线程之间共享的任何信息都需要同步,或者至少要使用volatile 未共享的信息可以保留。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM