Thread only running correctly if there is a System.out.println() inside the while true loop
Basicly, I'm making a game which to update the players position, it uses this thread:
@Override
public void run() {
while(true) {
System.out.println();
updatePos(x, y);
}
}
Which works fine, but if I remove the System.out.println(), it ceases to function. I have no idea why this is, the whole class is as follows:
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() == Key开发者_C百科Event.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);
}
}}
Final note: Ingore the boolean upPresses and downPressed, the only thing I'm focusing on is this:
if (e.getKeyCode() == KeyEvent.VK_UP) {
y -= speed;
}
A loop like
while(true) {
updatePos(x, y);
}
would completely hog the CPU. Reason it starts behaving better with a println
is probably because you yield a few hundred cycles per iteration for I/O.
I suggest you add a small sleep-method according to the desired frame rate:
while (true) {
try {
Thread.sleep(10); // for 100 FPS
} catch (InterruptedException ignore) {
}
updatePos(x, y);
}
or, even better, go with an event driven approach with for instance a java.util.Timer
. (That would be more Java idiomatic.)
Don't know if that would solve it, but it looks like you're giving the JVM a hard time... Try adding a short sleep (which is the correct way to implement a game thread) before each updatePos(x, y) call.
@Override
public void run() {
while(true) {
Try
{
Thread.sleep(50);
}
catch (Exception e){}
updatePos(x, y);
}
}}
You didn't post the code to updatePos
. But at a minimum, you need to make that method, as well as keyPressed
(and anything else that uses x
and/or y
) synchronized
.
Alternatively you can make both x
and y
volatile
, but then x
and y
could get updated out of lockstep.
But without any memory synchronisation, changes from one thread are not guaranteed to be observable from another thread.
A Thread.yield()
can also do it in some cases.
See https://www.javamex.com/tutorials/threads/yield.shtml for example.
The author of this link does not recommend to use yield
however.
There is yet another appoach. You can use class java.util.Timer that is dedicated for implementation of scheduled tasks. It is very useful if for example you need now 2 threads that periodically perform some kind of different operations. Using Timer you can save your efforts and computer resources using only one thread
精彩评论