2

I need this threads that have access to the same data to be execute simultaneously without messing around with each other, so instead using Thread.join() I've been trying with synchronized methods. Problem is that I see no change at all, it keep giving me the same result that I had before using them. I don't even know what exactly I'm doing wrong, synchronized methods suppose to prevent other synchronized methods to execute until they are done, right? Hope you can give me some clue about what is goin' on.

public class ThreadSync{
    public static void main(String[] args) throws InterruptedException {
         //if execute properly  
         //output can't be other than 0
         while(true) {
         ChangeValue counter = new ChangeValue();
         Threads t  = new Threads(counter,"up");
         Threads t2 = new Threads(counter,"down");
         Threads t3 = new Threads(counter,"print");
         t.start();
         t2.start();
         t3.start();
         }
    }
}
class Threads extends Thread{
    Threads(ChangeValue obj, String act){
        counter = obj;
        action = act;
    }
    @Override
    public void run() {
        switch(action) {
        case ("up"):    counter.up();    break;
        case ("down"):  counter.down();  break;
        case ("print"): counter.print(); break;     
        }
    }
    ChangeValue counter;
    String action;
}
class ChangeValue{  
    public synchronized void up()    { value++; }
    public synchronized void down()  { value--; }
    public synchronized void print() { System.out.println(value); }
    public int value = 0;
}
nrainer
  • 2,542
  • 2
  • 23
  • 35
MikeDvP
  • 23
  • 3
  • You wrote in your question: _Problem is that I see no change at all, it keep giving me the same result that I had before using [threads]_ What "result" are you expecting? – Abra Aug 21 '20 at 07:34

2 Answers2

5

The synchronization just ensures that the methods are not executed at the same time. However, it does not guarantee any execution order.

You need to ensure that print() is not executed before the other threads have terminated. This could be achieved by joining the threads. To do so, execute

t.join();
t2.join();

either before starting the print thread or before executing its logic.

Note that the synchronization is still sensible because it ensures that the increment and decrement operations are executed atomically. That is, that reading, incrementing, and writing count when executing count++ are executed at once (see also: Why is i++ not atomic?). Thereby it prevents the following execution sequence:

  • [Thread "up"]: load count with value 0
  • [Thread "down"]: load count with value 0
  • [Thread "up"]: increment count to 1
  • [Thread "down"]: decrement count to -1
  • [Thread "up"]: store count with value 1
  • [Thread "down"]: store count with value -1

(This is a "lost update" in database terms.)

nrainer
  • 2,542
  • 2
  • 23
  • 35
  • So I can't pretend synchronized methods to work just like joining threads. Now I get it, thanks, now I can make a better test to see how this work. :) – MikeDvP Aug 21 '20 at 07:59
2

synchronized prevens your thread from accessing the field simultaneously, but of course it provides no guarantee regarding the order in which the threads execute. For example, if, by pure chance, the "Up" thread executes first, the "Print" thread second and the "Down" thread last, the output will be 1, even though the counter value is 0 after all threads are finished.

Erich Kitzmueller
  • 36,381
  • 5
  • 80
  • 102