My program is based on two threads that share a protocol object. Depending on a boolean in the shared protocol object I try to make the other thread wait before using the protocol.
Main:
GameProtocol protocol = new GameProtocol();
MyThreadedClass thread1 = new MyThreadedClass(protocol);
MyThreadedClass thread2 = new MyThreadedClass(protocol);
thread1.start()
thread2.start()
Thread class:
GameProtocol protocol;
private MyThreadedClass(GameProtocol protocol){
this.protocol = protocol
}
private GamePackage waitCheck(GamePackage gp){
if(!gp.isWaiting()) {
return protocol.update(gp);
}
while(protocol.waitForCategory) {
//System.out.println(protocol.waitForCategory);
}
return protocol.update(gp);
}
Protocol class:
boolean waitForCategory = false;
public synchronized GamePackage update(GamePackage gp){
if(gp.myTurnToPickCategory){
gp.setWaiting(false);
waitForCategory = true;
} else {
gp.setWaiting(true);
waitForCategory = false;
}
return gp;
}
Now my intention is to make one thread wait untill the other thread have used the update method a second time. But the second thread get stuck in the while loop even tho the boolean waitForCategory
have been set to false. Once I added the line System.out.println(protocol.waitForCategory);
however it just started to work, and if I remove it it stops working again. I can't seem to understand how a ´sout´ on the boolean make it work. If anyone understands this would it be possible to solve it in another way? as having a sout inside a loop like that will make it messy.
CodePudding user response:
Here is the explanation for why println makes the code work: stackoverflow.com/q/25425130/217324 – Nathan Hughes
CodePudding user response:
As others have already explained, the introduction of println()
inserts synchronization into the picture, so your code gives the illusion that it works.
In order to solve this problem you have to make sure everything is properly synchronized. In other words, gp.isWaiting()
must also be synchronized, and protocol.waitForCategory
must be moved into a method and synchronized.
Alternatively, quit trying to work with synchronization and use asynchronous message passing via java.util.concurrent.BlockingQueue
instead. Your code will perform better, you will not be running the danger of race conditions, and your code will also be testable. (Whereas with synchronization your code will never be testable, because there is no test that will catch a race condition.)