1

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.

  • Your program lacks synchronization, therefore the results are unpredictable. Inserting a print call just changed it from 'unpredictable and not what you want' to 'unpredictable that looks like what you want'. But that doesn't make the code correct. – access violation Nov 27 '22 at 02:28
  • Here is the explanation for why println makes the code work: https://stackoverflow.com/q/25425130/217324 – Nathan Hughes Nov 27 '22 at 02:38
  • @access violation I totaly agree that I don't know what correct code is but i am using `synchronized` on my protocol update method. Should have stated it. – Gustav Henriksson Nov 27 '22 at 02:45
  • This access is unsynchronized: `while(protocol.waitForCategory)` – access violation Nov 27 '22 at 02:58

1 Answers1

0

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.)

Mike Nakis
  • 56,297
  • 11
  • 110
  • 142
  • Interesting. I've comed across it after reading up about threads just now. In my application I have two clients who runs 2 seperate threads on a server. the 2 threads on the server share a common object where values get added to either of each packages and then resends to the client who sended it. If i would like to use a blockingqueue object to validate if one of the threads is allowed to enter their shared protocol object based on a boolean where would make the most sense to implement it? in the protocol or in the theads? – Gustav Henriksson Nov 27 '22 at 21:54
  • Asynchronous message passing using message queues is used in an entirely different way. It will require that you stop thinking the old way and start thinking the new way. With message passing, you do not share data among threads; instead, you pass data from one thread to the other in an immutable message, and you have the results communicated back via another immutable message. So, there is nothing to "allow to enter". – Mike Nakis Nov 28 '22 at 00:33
  • Another beautiful thing with message passing is that you do not even have to run it in multiple threads; you can run it in sync, so it is easier to debug. And once you know it works in sync, you can run it in multiple threads for better performance. – Mike Nakis Nov 28 '22 at 00:36