[英]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问题上看到了这一点。 我将尝试查找它以获取更多信息。
之所以发生您的问题,是因为输出流的打印阻塞了当前线程,并且desiredHealth
和player.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.