0

だから私はこのJavaアプレットを作っています。もっと複雑にする前に、まずキー入力が正しく機能することを確認したいだけです。理由はわかりませんが、「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;
            }           
        }           
    }
}
4

3 に答える 3

4

このコードには重大な問題があります。まず第一に、正当な理由もなく Runnable を実装しています。第二に、あなたの run() メソッドは大きなビジー待機ループです。そして 3 つ目はもちろん、needsUpdating 変数での同期の欠如です。

スレッドセーフでない needsUpdating 変数を使用する代わりに、リスナー メソッドで必要な操作を実行する必要があります。これにより、イベント ディスパッチ スレッドに移動するため、スレッド セーフの問題は解消されます。

于 2013-07-02T13:49:16.967 に答える
1

フィールドneedUpdatingvolatile次のようにする必要があります。

volatile boolean needUpdating;

この動作は、メソッド内の無限ループによって定義されますrun()。JVM はneedUpdatingフィールドの値をキャッシュします。

UPD:コードを確認しました: volatilefield の修飾子で問題なく動作needUpdatingするため、私の答えが解決策です。

UPD2:この問題を明確にするために、JLS7: 17.3 の第 17 章の例を見てください。スリープ アンド イールド

于 2013-07-02T13:48:05.927 に答える