2013-07-02 2 views
0

Итак, я делаю этот java-апплет, и я просто хочу сначала убедиться, что ввод ключа работает правильно, прежде чем сделать его более сложным. Я понятия не имею, почему, но когда вы удаляете «System.out.print (needUpdating)»; он неправильно перемещает прямоугольник в соответствии с вводом ключа. Может ли кто-нибудь сказать мне, почему и как это исправить? Для меня это полная тайна.Boolean не корректно обновляется, если вы не печатаете его

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

Попытайтесь сделать поле 'needUpdating'' volatile': 'volatile boolean needUpdating;' – Andremoniy

ответ

5

Ваш код некорректно синхронизирован. Лучше сказать, он не синхронизирован вообще. Однако System.out.println является синхронизированным методом и на современных типичных архитектурах процессора вход в синхронизированный блок реализуется как предел памяти на уровне исходного кода. Это приводит к тому, что изменения в вашем логическом значении видимы для других потоков.

Заключение: правильно синхронизируйте свой код, и «магическое» поведение исчезнет.

+0

Я исправил эту ошибку и обнаружил, что прямоугольник поднимается, когда вы нажимаете стрелку вниз. – johnchen902

+1

Это не удивительно, так как вы уменьшаете 'y' в этом случае, а начало координат системы - в верхнем левом углу. –

1

Вы должны сделать ваше поле needUpdating в volatile:

volatile boolean needUpdating;

Такое поведение определяется бесконечным циклом внутри run() метода: JVM кэширует значение needUpdating поля.

UPD: Я только что проверил код: он прекрасно работает с volatile модификатора на поле needUpdating, так что мой ответ является решением.

UPD2: Для уточнения этой проблемы, посмотрите, например, в главе 17 JLS7: 17.3. Sleep and Yield

4

Есть серьезные проблемы с этим кодом. Прежде всего вы внедряете Runnable без уважительной причины. Во-вторых, ваш метод run() представляет собой большой цикл ожидания занятости. И в-третьих, конечно, отсутствие синхронизации в ваших потребностях.

Вместо использования небезопасных потребностей. Обновляемая переменная, вы должны выполнить необходимые операции в методах прослушивания, и проблема безопасности потоков исчезнет, ​​так как вы попадете в Thread Dispatch Thread.

Смежные вопросы