Boolean not changing in thread - java

I have a class MPClient and MultiplayerMatch. MultiplayerMatch, in his constructor, creates a MPClient runnable thread.
To avoid data overflow, I have a boolean named "moved" in MultiplayerMatch that changes to true when the player is moving.
In the updateMatch method, if there's any player movement, "moved" changes to true, which allow MPClient to enter an if statment (inside while). This way MPClient only sends data to the server when something changes on the game.
Neverthless, when the flag is true, in MPClient that change is not registed! MPClient still "thinks" moved equals false, even after that flag changed in MultiplayerMatch, and as a consequence, nothing is sent to the server...
After a few tests, I noticed that if I run it in Debug Mode, since I have some breakpoints, that change is registered and everything works great!
Why is the boolean change only "seen" though Debug Mode? Does it have something to do with the app "running speed", since there are breakpoints?
Here's only the important part of the code:
MPClient:
public class MPClient {
static final int TIME_OUT = 5000;
Client client;
MultiPlayMatch match;
public MPClient(String name, int team, MultiPlayMatch match) {
this.match = match;
client = new Client();
client.start();
Network.registerPackets(client);
addListeners();
try {
client.connect(TIME_OUT, "127.0.0.1", Network.PORT);
} catch (IOException e) {
e.printStackTrace();
client.stop();
}
/*this comment is just to show that here is the place where the login information is sent to the server, instead of showing all the code*/
PlayerInfo playerInfo = new PlayerInfo();
Network.UpdatePlayer updatePlayer = new Network.UpdatePlayer();
updatePlayer.name = name;
updatePlayer.team = team;
while(true) {
if(match.moved) { //--> this is the variable that is always false
playerInfo.x = match.getClientPlayerX(team);
playerInfo.y = match.getClientPlayerY(team);
updatePlayer.x = playerInfo.x;
updatePlayer.y = playerInfo.y;
client.sendTCP(updatePlayer);
match.moved = false;
}
}
}
private void addListeners() {
client.addListener(new Listener.ThreadedListener(new Listener() {
#Override
public void received(Connection connection, Object object) {
if(object instanceof Network.UpdatePlayer) {
Network.UpdatePlayer updatePlayer = (Network.UpdatePlayer) object;
match.setPlayerPosition(updatePlayer.x, updatePlayer.y, updatePlayer.name, updatePlayer.team);
}
}
}));
}
}
MultiplayerMatch:
public class MultiPlayMatch extends Match {
public boolean moved;
public MultiPlayMatch(){
super(0);
Random r = new Random();
int aux = r.nextInt(2);
aux = 0;
if(aux == 0){
homeTeam = new Team("Benfica", Team.TeamState.Attacking, w);
visitorTeam = new Team("Porto", Team.TeamState.Defending, w);
} else{
homeTeam = new Team("Benfica", Team.TeamState.Defending, w);
visitorTeam = new Team("Porto", Team.TeamState.Attacking, w);
}
//homeTeam.controlPlayer(0);
numberOfPlayers = 0;
moved = false;
}
#Override
public void updateMatch(float x, float y, Rain rain, float dt) {
homeTeam.updateControlledPlayerOnline(x, y);
rain.update();
w.step(Constants.GAME_SIMULATION_SPEED, 6, 2);
if(x != 0 || y != 0) moved = true; //this is the place the variable is changed, but if it isn't in debug mode, MPClient thinks it's always false
}
public void setPlayerPosition(float x, float y, String name, int team) {
if(team == 0)
homeTeam.changePlayerPosition(x, y, name);
else
visitorTeam.changePlayerPosition(x, y, name);
}
}

volatile
This is because it is reading a cached value of match.moved variable instead of the latest. To avoid this, declare the variable as volatile
public volatile boolean moved;
Read more here

tl;dr
AtomicBoolean is a convenient alternative to volatile.
This class wraps and protects a nested primitive boolean value while ensuring proper visibility.
Instantiate:
public final AtomicBoolean moved = new AtomicBoolean( false ) ;
Getter:
boolean x = moved.get() // Returns current value.
Setter:
moved.set( false ) // Sets a new value.
Get, then set:
boolean x = moved.getAndSet( false ) ; // Retrieves the old value before setting a new value.
AtomicBoolean
The Answer by agamagarwal is correct. You have fallen into the visibility conundrum that occurs when accessing variables across threads. One solution is the use of volatile shown there.
Another solution is the Atomic… classes bundled with Java. In this case, AtomicBoolean.
The Atomic… classes wrap a value, and add thread-safe methods for accessing and setting that value.
I often prefer using the Atomic… classes rather than volatile. One reason for this preference is that it makes quite clear and obvious to the user that we are using a protected resource across threads.
Instantiation:
public class MultiPlayMatch extends Match {
public final AtomicBoolean moved = new AtomicBoolean( false ) ;
…
Notice two things about that instantiation:
final ensures that we do not swap out one AtomicBoolean object for another. Such swapping would put us right back into the variable visibility conundrum we are trying to escape.
The AtomicBoolean object is being instantiated at the same time as this outer object (MultiPlayMatch in your case) is being instantiated. So we have ensured that an instance of AtomicBoolean exists before any access, including any access across threads. If we waited until later (“lazy” loading), then we would be falling back into that variable visibility conundrum we are trying to escape.
Getting the value:
if ( this.match.moved.get() ) { … // Returns the primitive `true` or `false` value wrapped within this `AtomicBoolean` object.
And setting the value:
this.match.moved.set( false ) ;
You may want to get the current value while also setting a value in an immediate thread-safe “atomic” (combined) operation:
boolean oldValue = this.match.moved.getAndSet( false ) ;
To learn all about concurrency in Java, see the book, Java Concurrency in Practice by Brian Goetz, et al.

Related

Updating original values after passing them as params to a new method instead of references

I have a method whose some parts of are repetitive. I managed to split the code in a way that the original method uses smaller methods many times. The problem is that when I pass some values as params to those new smaller methods and work with them, original values don't get updated. The actions I do are: value incrementation or removing items from arraylist. How do I update the original values using the smaller methods, not only the references? The only possible solution I came up with is to create a new class where I could have a setter for those values and update them. But are there easier/straightforward ways to solve it?
Part of the main method:
int numberOfBlocks = 0;
int currentBlock = 0;
int currentTime = 0;
ArrayList<Request> queue = new ArrayList<Request>();
if(queue.size != 0) {
updateStatus(queue, currentBlock, numberOfBlocks);
}
if(something else happens) {
removeFinished(queue, currentBlock);
}
Smaller methods:
private void updateStatus(ArrayList<Request> queue, int currentBlock, int numberOfBlocks) {
if (queue.get(0).getBlock() > currentBlock)
currentBlock++;
else
currentBlock--;
numberOfBlocks++;
}
private void removeFinished(ArrayList<Request> queue, int currentBlock){
if (queue.get(0).getBlock() == currentBlock) {
queue.remove(0);
}
}
First of all, if you pass a parameter in order for it to be changed in the method, your method should return the changed value, this will resolve your issue. If more then one value needs to be changed, then you are correct, primitives are passed y value and the invoking method doesn't see the changes made in the invoked method. So you should encapsulate those values in a wrapping class with setters and getters like you wanted to. That alone will resolve your problem. But also it would make sense for your method to return that class since it is modified. This is just a good stile
If the smaller methods are in the same class as the main method, simply don't pass them as parameters and the methods will use the class's fields. This is non-thread safe, but your class is non-thread safe already anyway.
class MyClass
{
int numberOfBlocks = 0;
int currentBlock = 0;
int currentTime = 0;
ArrayList<Request> queue = new ArrayList<Request>();
void myMainMethod() {
if(queue.size != 0) {
updateStatus();
}
if(something else happens) {
removeFinished();
}
}
private void updateStatus() {
if (queue.get(0).getBlock() > currentBlock)
currentBlock++;
else
currentBlock--;
numberOfBlocks++;
}
private void removeFinished() {
if (queue.get(0).getBlock() == currentBlock) {
queue.remove(0);
}
}

Boolean switch outside of lambda

Im working on a game in JavaFX. It's almost done but I encountered problem with move detection and can't think of simple solution. There probably is, but I'm just not aware of that
Obviously there is more code in between but i'm highlighting the problematic part.
int finalX = x;
int finalY = y;
boolean jumpMade = false;
boolean moveMade = false;
// Mouse Controller
board[x][y].setOnMouseClicked(event -> {
if (!moveMade) {
move(finalX, finalY, selectedMarbleX, selectedMarbleY, selectedMarbleColor);
// Here I would want to make moveMade = true;
// To block further possibility of moving.
}
}
Tried changing to atomic or into one-element array but that won't do the job because the "map" that user is playing on have more than one possible direction of moving (so it wont block all of them).
And the error that appears by just placing nonchalantly moveMade = true overthere brings up "Variable in lambda expression should be final or effectively final".
Use java.util.concurrent.atomic.AtomicBoolean utility class. They hold an atomic thread-safe reference to a value.
import java.util.concurrent.atomic.AtomicBoolean;
// Outside of lambda, instantiate the atomic boolean reference
AtomicBoolean ref = new AtomicBoolean(); // Constructor parameter optional: empty (false) / true / false
// Inside lambda, use the getters and setters
ref.set(true); // or: ref.set(false);
If you wish to access and modify the variable in a lambda expression, define it as a class/instance variable. There is a genuinely crux reason for the error you shouldn't rule out.
Gobbledygook yet a simple example,
interface Q {
void fun();
}
class ABC {
public static boolean x = false; // class variable
public static void b(Q q) {
q.fun();
}
public static void main(String[] args) {
Q a = () -> {
System.out.println("run simple lambda");
x = true;
};
b(a);
System.out.println(x);
}
}

Break loop from another class java

I'm currently working on somekind text-based 'RPG' game. I made two classes, first one is supposed to simulate road from one town to another and doing so there is a possibility that player will encounter enemy. Fighting logic is placed in another class and when player dies I call method which is supposed to load game from previous save or create new character and that works perfectly fine, but even when player died road is continued instead of breaking loop. LeaveTown class looks like this:
public class WorldMap {
boolean running=true;
public void leaveTown(Character character){
EnemyFactory factory = new EnemyFactory();
PerformAtack atack = new PerformAtack();
StringBuilder sb = new StringBuilder();
Random random = new Random();
int progress = 0;
while(running && progress!=100){
try {
System.out.print(sb.append("#"));
System.out.println(progress+"%");
if (random.nextDouble() * 10 < 2) {
atack.performFight(character,factory.generateRandomEnemy());
}
Thread.sleep(500);
}catch(Exception ex){}
progress = progress+5;
}
}
}
As you can see, I'm using while loop which is supposed to break when running variable is set to false or road is finished. When character dies I call method battleLost:
private void battleLost(Character character){
WorldMap map = new WorldMap();
System.out.println("You are dead.\nWould you like to try AGAIN or LOAD your last save");
System.out.println("Please type AGAIN or LOAD");
while(true) {
String choice = sc.nextLine().toUpperCase();
if (choice.equals("AGAIN")) {
map.running = false;
System.out.println("Create new character?");
break;
} else if (choice.equals("LOAD")) {
map.running = false;
save.readFromFile();
break;
} else
System.out.println("Try again.");
}
}
This method sets running variable in class WorldMap to false, but the while loop is continued instead of breaking. Im aware that problem is probably linked to using map.running = false; in wrong way.
I'd glad if anyone could explain me how this problem should be solved.
boolean running=true;
This variable should be part of Character class.
then, your while will just look like:
while(character.isRunning() && progress!=100)
and, within performFight you can update it to false when died.
I guess battleLost() belongs to PerformAtack class. so the local variable map inside the battleLost() does not affect the object that is controlling the road.
You can do two things:
make running static (and public) and then you can reference it from anywhere by the class name like this WolrdMap.runnning = false but this solution has problems if you decide to do things in parallel (e.g. multiple threads). Remmeber: static data is almost always a pitfall for multi-threaded design!
a better solution is to make atack.performFight return a boolean value and assign that value to the running var: running = atack.performFight(... this is better design in terms of thread safety, but you will have to propagate the boolean value from battleLost() (it too will have to return boolean) to `performFight()' and so on
Well,Change the access modifier for variable boolean running=true; to public static boolean running=true;
once you did that you can change this variable to false without creating an instance in order to break the loop, do something like that
private void battleLost(Character character){
WorldMap map = new WorldMap();
System.out.println("You are dead.\nWould you like to try AGAIN or LOAD your last save");
System.out.println("Please type AGAIN or LOAD");
while(WorldMap.running) {
String choice = sc.nextLine().toUpperCase();
if (choice.equals("AGAIN")) {
map.running = false;
System.out.println("Create new character?");
break;
} else if (choice.equals("LOAD")) {
map.running = false;
save.readFromFile();
break;
} else
System.out.println("Try again.");
}
public void breakTheLoop(){
WorldMap.running=false;
}
because of static is a class variable so it's value will be shared between all classes

Reset each variable in java

Is there a way to reset a value of a static variable to their initial state? For example:
I have a lot of variables which holds score, speed, etc. All those variables are changing during the program execution. So when the user fails in a game, I would like to reset ALL variables to their initial state. Is there some way? Because i don't know if it is a good idea to do this manually for EACH variable in my program. for example:
static int SCORE = 0;
static float SPEED = 2.3f;
public void resetGame() {
SCORE = 0;
SPEED = 2.3;
}
Use an object, and set its initial state in the constructor:
public class GameSettings {
private int score = 0;
private float speed = 2.3F;
// methods omitted for brevity
}
...
public void resetGame() {
gameSettings = new GameSettings();
}
Also, please respect the Java naming conventions. ALL_CAPS is reserved for constants. Variables should be lowerCase.
Store the default values.
static final int DEFAULT_SCORE = 0;
static final float DEFAULT_SPEED =2.3;
static int SCORE = DEFAULT_SCORE;
static float SPEED = DEFAULT_SPEED;
public static void resetGame() {
SCORE = DEFAULT_SCORE;
SPEED = DEFAULT_SPEED;
}
Why not just recreate the object if you want it reset? Then it'll implicitly have the default values.
You could just declare your variables without values and have a method initGamestate() which sets all variables to their initial values. Call this function both on initialization of the application and when the user starts a new game.
A more object-oriented solution would be to have a class GameState which has all these variables and sets the default in its constructor. You then start every game by initializing a fresh object with new GameState();
You'll just have to reset them one by one. If you're worried about typos you could do: int initialscore = 0; int score = initialscore; and then reset them to the initial... variables in your function.
I have a lot of variables which holds score, speed, etc
You should put them all into one class and every member get initialsed (if the default won't work).
You will hold the player's state in one reference to an object of this class. To reset simply create a new object of this class and assign it to the reference.
Usually games use more than one thread (for example when using Swing or painting any graphics), e.g. so inputs are not blocked. That means with all the other solutions you might run into race conditions. This solution of Evan Knowles came closest.
I would suggest a immutable GameState class, e.g.
public GameState {
private final int score;
private final int speed;
// initial state/"reset game"
public GameState() {
score = 0;
speed = 2.3;
}
// Private so we are always in a valid state
private GameState(int _score, int _speed) {
score = _score;
speed = _speed;
}
public GameState updateSpeed(int _speed) { return new GameState(this.score, _speed); }
public GameState updateScore(int _score) { return new GameState(_score, this.speed); }
public int getSpeed() { return speed;}
public int getScore() { return score;}
// add getters, setters and whatsoever here. But watch for proper synchronization between threads!
}
The advantage here is that once the values are assigned, they can't be changed anymore ("immutable"/read-only) from the outside, so there are no concurrency issues. Plus, you get a sort of chaing for free (see below)! Moreover, you can safely (de-)serialize the game state for saving/loading games.
Effectively, each GameState represents one state in a finite state machine. Calling either updateSpeed or updateScore is a transition to a new state.
The public default constructor is a transition to the initial state of the state machine.
On a side note, the state machine is finite because the value ranges of score and speed are finite, thus all combiniations of them result in a finite amount of states.
I now assume your class for doing other game stuff is called Game.
public Game {
private volatile GameState gameState = new GameState();
public void resetGame() {
gameState = new GameState();
}
// Just an example
public increaseSpeed(int _additionalSpeed) {
gameState = gameState.updateSpeed(gameState.getSpeed() + _additionalSpeed);
}
// Change more than one value
public changeBoth(int _newSpeed, int _newScore) {
// First way: Create a new GameState, change both values step by step and then assign afterwards.
GameState _newState = gameState.updateScore(_newScore);
// other computations follow
// Do NOT assign to gameSpate here, because the state would be inconsistent then.
_newState = _newState.updateSpeed(_newSpeed);
// At the END of the method, assign the new game state. That ensures that the state is always valid
gameState = _newState;
// Second way: Use method chaining if you don't need to make other computations in between. Again, do this at the end of the method
gameState = gameState.updateScore(_newScore).updateSpeed(_newSpeed);
}
}
The volatile keyword makes sure every thread sees the same value of the gameState variable. You might want to consider using other synchronization/locking techniques instead, too. Alternatively you can make the gameState field static and skip the volatile keyword if you only have one Game object.
Because GameState is immutable(read-only), the state of your game now is always consistent/valid.
A good way is to use a static init() and call it when exception occurs.
package com.kvvssut.misc;
public class ResetStatic {
private static int SCORE = 0;
private static float SPEED = 2.3f;
private static void init() {
SCORE = 0;
SPEED = 2.3f;
}
public static void main(String[] args) {
SCORE = 100;
SPEED = 230.3f;
try {
throw new RuntimeException();
} catch (Exception e) {
init();
}
System.out.println(SCORE);
System.out.println(SPEED);
}
}

AtomicReference Usage

Say you have the following class
public class AccessStatistics {
private final int noPages, noErrors;
public AccessStatistics(int noPages, int noErrors) {
this.noPages = noPages;
this.noErrors = noErrors;
}
public int getNoPages() { return noPages; }
public int getNoErrors() { return noErrors; }
}
and you execute the following code
private AtomicReference<AccessStatistics> stats =
new AtomicReference<AccessStatistics>(new AccessStatistics(0, 0));
public void incrementPageCount(boolean wasError) {
AccessStatistics prev, newValue;
do {
prev = stats.get();
int noPages = prev.getNoPages() + 1;
int noErrors = prev.getNoErrors;
if (wasError) {
noErrors++;
}
newValue = new AccessStatistics(noPages, noErrors);
} while (!stats.compareAndSet(prev, newValue));
}
In the last two lines
newValue = new AccessStatistics(noPages, noErrors);
while (!stats.compareAndSet(prev, newValue))
Does it means the new created AccessStatistics instance has same reference as the current AccessStatistics instance. how could it be ? Can Anyone explain it . Thanks a lot.
stats.compareAndSet(prev, newValue) will fail and return false if the current reference held by stats is not prev.
Typically, in a multi-threaded environment, it is very possible that between prev = stats.get(); and stats.compareAndSet(prev, newValue); another thread would have modified the reference held by stats.
stats.compareAndSet(prev, newValue); really says:
if stats still holds a reference to prev, as it was 5 lines before, update it to hold a reference to newValue
if however another thread has already changed the reference held by stats since I last checked 5 lines ago, discard my calculation and loop to recalculate a new newValue.
The newly created object is, well, new. After the line that it is created, the only thing that refers to it is newValue. Nothing else could -- how could it? The compareAndSet() only sets if nothing else has in the meantime set it to some third value, besides the old one you know about prev and the new one you made newValue.

Categories

Resources