所以我正在创建这个java applet,我只想首先确保键输入正常工作,然后再使它更复杂。我不明白为什么,但当你删除“System.out.print(needUpdating);”它没有根据键输入正确移动矩形。谁能告诉我为什么以及如何解决它?这对我来说完全是个谜。
import java.applet.Applet;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JApplet;
public class firstApplet extends JApplet implements KeyListener, Runnable {
final int MOVEAMOUNT = 1;
boolean needUpdating;
int x,y,dx,dy;
Thread runner = null;
public void init() {
this.setFocusable(true);
needUpdating = false;
this.requestFocusInWindow();
x=0;
y=0;
dx=0;
dy=0;
addKeyListener(this);
}
public void stop() {
}
public void start() {
runner = new Thread(this);
runner.start();
}
public void paint(Graphics g) {
System.out.println("x= "+x+" y = "+y);
g.drawRect( x, y, 100, 15 );
}
@Override
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if(key==KeyEvent.VK_UP) {
System.out.println("up");
dy=MOVEAMOUNT;
}
else if (key==KeyEvent.VK_DOWN) {
dy=-MOVEAMOUNT;
}
else if (key==KeyEvent.VK_LEFT) {
dx=-MOVEAMOUNT;
}
else if (key==KeyEvent.VK_RIGHT) {
dx=MOVEAMOUNT;
}
// TODO Auto-generated method stub
needUpdating = true;
System.out.println("needUpdating listening = " +needUpdating);
}
@Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
dx=0;
dy=0;
}
@Override
public void keyTyped(KeyEvent e) {
}
public void processMovement() {
System.out.println("processing");
x+=dx;
y+=dy;
}
@Override
public void run() {
this.addKeyListener(this);
while(true) {
System.out.print(needUpdating);
if(needUpdating) {
processMovement();
repaint();
needUpdating=false;
}
}
}
}
答案 0 :(得分:5)
您的代码未正确同步。更好的说,它根本不同步。但是,System.out.println
是一种同步方法,在当今典型的CPU架构中,进入同步块恰好在本机代码级实现为内存屏障。这样可以使对布尔值的更改对其他线程可见。
结论:正确同步你的代码,“魔法”行为将会消失。
答案 1 :(得分:4)
此代码存在严重问题。首先,你没有充分的理由实现Runnable。其次,run()方法是一个繁忙的等待循环。第三,当然缺少需求更新变量。
您应该在侦听器方法中执行所需的操作,而不是使用线程不安全的needsUpdating变量,并且线程安全问题将消失,因为您将进入事件调度线程。
答案 2 :(得分:1)
您必须将字段needUpdating
设为volatile
:
volatile boolean needUpdating;
此行为由run()
方法内的无限循环定义:JVM缓存needUpdating
字段的值。
UPD:我刚刚检查了您的代码:它在volatile
字段上使用needUpdating
修饰符时效果很好,所以我的答案就是解决方案。
UPD2:为澄清此问题,请查看JLS7第17章中的示例:17.3. Sleep and Yield