Java 仅当while true循环中存在System.out.println()时,线程才能正确运行
基本上,我正在制作一个更新玩家位置的游戏,它使用以下线程:Java 仅当while true循环中存在System.out.println()时,线程才能正确运行,java,multithreading,Java,Multithreading,基本上,我正在制作一个更新玩家位置的游戏,它使用以下线程: @Override public void run() { while(true) { System.out.println(); updatePos(x, y); } } 这很好,但是如果我删除System.out.println(),它就会停止工作。我不知道这是为什么,全班如下: public class Player extends Block implements KeyLis
@Override
public void run() {
while(true) {
System.out.println();
updatePos(x, y);
}
}
这很好,但是如果我删除System.out.println(),它就会停止工作。我不知道这是为什么,全班如下:
public class Player extends Block implements KeyListener, Runnable {
int x;
int y;
int speed;
boolean upPressed;
boolean downPressed;
boolean rightPressed;
boolean leftPressed;
static Sprite sprite = new Sprite("grass.png");
public Player(int x, int y, int speed) {
super(x, y, sprite);
this.x = x;
this.y = y;
this.speed = speed;
Thread playerThread = new Thread(this, "Player Thread");
playerThread.start();
}
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_UP) {
y -= speed;
}
if (e.getKeyCode() == KeyEvent.VK_DOWN)
downPressed = true;
if (e.getKeyCode() == KeyEvent.VK_RIGHT)
rightPressed = true;
if (e.getKeyCode() == KeyEvent.VK_LEFT)
leftPressed = true;
}
@Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_UP)
upPressed = false;
if (e.getKeyCode() == KeyEvent.VK_DOWN)
downPressed = false;
if (e.getKeyCode() == KeyEvent.VK_RIGHT)
rightPressed = false;
if (e.getKeyCode() == KeyEvent.VK_LEFT)
leftPressed = false;
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void run() {
while(true) {
System.out.println();
updatePos(x, y);
}
}}
最后一点:关于布尔上下压,我唯一关注的是:
if (e.getKeyCode() == KeyEvent.VK_UP) {
y -= speed;
}
环状
while(true) {
updatePos(x, y);
}
会完全占用CPU。使用println
它开始表现得更好的原因可能是因为每次迭代I/O都会产生几百个周期
我建议您根据所需的帧速率添加一个小的睡眠方法:
while (true) {
try {
Thread.sleep(10); // for 100 FPS
} catch (InterruptedException ignore) {
}
updatePos(x, y);
}
或者,更好的方法是采用事件驱动方法,例如。(这更像是Java惯用语。)我不知道这是否能解决问题,但看起来你给JVM带来了一段艰难的时光。。。 尝试在每次updatePos(x,y)调用之前添加一个短睡眠(这是实现游戏线程的正确方法)
}}您没有将代码发布到
updatePos
。但至少,您需要使该方法,以及按下键
(以及使用x
和/或y
的任何其他方法)同步
或者,您可以将x
和y
都设置为volatile,但是x
和y
可能会不同步地更新
但是,如果没有任何内存同步,一个线程的更改就不能保证可以从另一个线程看到。还有另一种方法。您可以使用java.util.Timer类,该类专用于执行计划任务。例如,如果您现在需要2个线程周期性地执行某种不同的操作,那么它非常有用。使用计时器,您只需使用一个线程即可节省工作和计算机资源。在某些情况下,yield()也可以这样做。 例如,见。
本链接的作者不建议使用
yield
但是。到底是什么不正常工作?它跑吗?是否输入updatePos?您可以使用断点来发现…您接受了修复问题的答案。但是,您的代码未同步,并且无法在其他一些计算机上工作,因此您也应该修复同步问题。此外,从构造函数启动线程被认为是一种不好的做法。可能是+1的重复,这可能是因为System.out.println()
非常昂贵,无意中“修复了”问题。@Kublai:可能更多,因为System.out.println
是同步的。@Chris为了在GUI线程和正在运行的线程之间进行有效的同步,GUI线程中的某些东西有时必须锁定在System.out.println使用的同一个锁上(无论该锁是什么)。甚至睡眠(0)
确实对我有用。我还不知道为什么。但是如果没有sleep(x)
,线程中while循环之后的指令将永远不会在线程停止时被调用。使用sleep(x)
(即使使用sleep(0)
)循环后的指令在我停止线程时被调用。这很有趣。哦,我在上面的问题上找到了我自己的答案:@Deza如果你对线程和同步知之甚少,请给出更详细的解释:keyPressed
是从Swing线程调用的,因此该线程中的值y
(一个cpu核心上的缓存具有新的y
值)。但是,运行run
和updatePos
的线程可能运行在另一个cpu核心上,而本地缓存不知道它应该更新y
(除非同步代码)。
@Override
public void run() {
while(true) {
Try
{
Thread.sleep(50);
}
catch (Exception e){}
updatePos(x, y);
}