Java 除非打印,否则无法正确更新布尔值

Java 除非打印,否则无法正确更新布尔值,java,swing,applet,boolean,Java,Swing,Applet,Boolean,因此,我正在制作这个java小程序,我只想首先确保键输入正确,然后再使其更复杂。我不知道为什么,但是当您删除System.out.printneedUpdating;它无法根据按键输入正确移动矩形。谁能告诉我为什么以及如何修复它?这对我来说完全是个谜 import java.applet.Applet; import java.awt.Graphics; import java.awt.Rectangle; import java.awt.event.KeyEvent; import java.

因此,我正在制作这个java小程序,我只想首先确保键输入正确,然后再使其更复杂。我不知道为什么,但是当您删除System.out.printneedUpdating;它无法根据按键输入正确移动矩形。谁能告诉我为什么以及如何修复它?这对我来说完全是个谜

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;
            }           
        }           
    }
}

您的代码同步错误。更好地说,它根本不是同步的。然而,System.out.println是一种同步方法,在当今典型的CPU体系结构上,输入同步块恰好在本机代码级别实现为内存屏障。这会使对布尔值的更改对其他线程可见


结论:正确地同步代码,神奇的行为就会消失。

你必须让你的领域变得易变:

易变布尔更新

这种行为由无限循环内部运行方法定义:JVM缓存needUpdating字段的值

UPD:我刚刚检查了你的代码:它在字段需要更新时与volatile修饰符一起工作很好,所以我的答案是解决方案


UPD2:要澄清此问题,请参阅JLS7第17章中的示例:

此代码存在严重问题。首先,您实现Runnable没有什么好的理由。其次,您的run方法是一个大的忙等待循环。第三,当然,您的needsUpdating变量中缺少同步


不要使用线程不安全的NeedsUpdated变量,您应该在侦听器方法中执行所需的操作,线程安全问题将消失,因为您将在事件分派线程中。

尝试使NeedUpdated字段变为volatile:volatile boolean needUpdated;我修正了这些错误,发现按下向下箭头时矩形向上。这并不奇怪,因为在这种情况下减少了y,坐标系的原点是左上角。