Java Why aren't variable values ​​shared between threads?

Question:

I have a class running on a thread that all it does is call a "handler" that tells it whether or not a key has been pressed on the keyboard.

Basically the KeyEvent detects if any key has been pressed, and if it is one of the keyboard arrows, it saves true to up, down, left or right.

So far so good.

The problem comes when the getPressedKey method starts, when it enters that method, the 4 booleans are false, that is, the keyPressed method has updated the booleans in its thread, but not in the thread that executes the getPressedKey method.

I have made the boolean 'volatile', but I don't see any improvement.

Edit with minimal example:

MainApp.java

public class MainApp {

public static void main(String[] args) {

    Frame f = new Frame();
    f.setVisible(true);

    Game j = new Game();
    Player p = new Player(j);

    p.start();

}

}

Frame.java

import javax.swing.JFrame;

public class Frame extends JFrame{

private static final long serialVersionUID = 1L;

Game panel = new Game();

public Frame() {
    super();
    initialize();
}

private void initialize() {
    this.setTitle("Evitar objeto");
    this.add(panel);
    this.setDefaultCloseOperation(EXIT_ON_CLOSE);
    this.setSize(600,600);
    this.setLocationRelativeTo(null);
    this.setVisible(true);
    this.setResizable(false);
    panel.addKeyListener(panel);
    panel.setFocusable(true);
}
}

Player.java

public class Player extends Thread{

public int x, y;
private boolean playing;
private Game game;

public Player(Game j) {

    x = 300-15;
    y = 300-28;
    playing = true;
    game = j;
}



public void run() {

    try {

        while(playing) {

            sleep(500);

            System.out.println(game.getPressedKey());
        }

    }catch(InterruptedException e) {}

}

}

Game.java

import java.awt.Graphics;
import java.awt.Image;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.Timer;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.ActionEvent; 

public class Game extends JPanel implements ActionListener, KeyListener {

private static final long serialVersionUID = 1L;

private Timer timer;

private Image player;

public int x, y, x_pelota, y_pelota;
private volatile boolean up;
private volatile boolean down;
private volatile boolean left;
private volatile boolean right;

private Player p;

public Game(){

    resetArrows();

    ImageIcon pertsonaiaIcon = new ImageIcon();
    player = pertsonaiaIcon.getImage();

    timer = new Timer(15, this);
    timer.start();
}

private void resetArrows() {
    up = false;
    down = false;
    left = false;
    right = false;
}

public int getPressedKey() {
    int ret;
    if (up) {
        ret = 0;
    }else if (down) {
        ret = 1;
    }else if (left) {
        ret = 2;
    }else if (right) {
        ret = 3;
    }else {
        ret = -1;
    }

    resetArrows();

    return ret;
}

@Override
public void paint(Graphics g){
    super.paint(g);
    g.drawImage(player, 0, 0, this);
}

@Override
public void actionPerformed(ActionEvent e){ 
    repaint();
}

@Override
public synchronized void keyPressed(KeyEvent e) {
    int keyCode = e.getKeyCode();
    switch(keyCode) { 
    case KeyEvent.VK_UP:
        resetArrows();
        up = true;
        break;
    case KeyEvent.VK_DOWN:
        resetArrows();
        down = true;
        break;
    case KeyEvent.VK_LEFT:
        resetArrows();
        left = true;
        break;
    case KeyEvent.VK_RIGHT :
        resetArrows();
        right = true;
        break;
    }
}

@Override
public void keyReleased(KeyEvent e) {}

@Override
public void keyTyped(KeyEvent e) {}


}

Answer:

As I imagined, the problem is that you have two different instances of the Game class:

In the MainApp class there is

Game j = new Game();

And in the Frame class you have

Game panel = new Game();

The solution goes through (for example), changing main to :

public static void main(String[] args) {

    Frame f = new Frame();
    f.setVisible(true);

    Game j = f.panel; // en lugar de crear un nuevo Game, usamos el ya creado
    Player p = new Player(j);

    p.start();

}
Scroll to Top