Java synchronisation and threads

Viewed 82
import java.util.Random;

public class ClassA{
  int a = 0, b = 10;
  Random rand = new Random();

  public synchronized void add(){
      if (a < 10){ 
         a++;
         b--;
      };
  }

  public synchronized void subtract(){
      if (b < 10){ 
         b++;
         a--;
      }
  }
  
  public synchronized boolean check(){
     return a + b == 10;
  }
  
  
  public static void main(String args[]){
      
      ClassA a = new ClassA();
      
      B ba = new B(a);
      B bb = new B(a);
      
       //notice these two threads are not associated with the object a!
      Thread t11 = new Thread(bb);
      Thread t22 = new Thread(ba);
      t11.start(); 
      t22.start();
  }
}


class B implements Runnable{
    ClassA a;
    
    B(ClassA a){
        this.a = a;
    }
   
    @Override
    public void run(){
        while (a.check()){
          if (a.rand.nextInt(2) == 1)
              a.subtract();
          else
              a.add();
      } System.out.print("Out of sync");
    }
}

I'm trying to understand java multi-threading better. So, I know that the saying goes only one thread can access an object instance and thus call that instance's method (in this case for example, the subtract method in class classA.

But what happens when, you still have the same instance of classA, a but two threads associated with a different class classB altogether trying to call a's methods? I expected that the message out of sync would never have been printed, but it did. Afterall, there's still only one object instance a, does that imply synchronization doesn't apply in this example?

1 Answers

In your case, out of sync would never be printed, because for your situation, the multithreading is implemented correctly: The critical methods that perform a sequence of operations and are thus not atomic are made behave like atomic methods by the using the synchronized keyword on the method.

Assume a code block is declared synchronized (x). The first thread that enters this code block obtains the lock of object x and happily executes that code block.

Any non-first thread that tries to enter the block on the same object x is "suspended" by putting the thread in the lock pool of x. As soon as the thread that currently has the lock leaves the synchronized (x) block, a random thread from the lock pool becomes the next thread to execute that block.

When using synchronized on an instance method, it is effectively the same as wrapping the entire content of the method with synchronized (this). (For static methods, it would be the class object of the enclosing class.)

So, in your case, there is one instance of class A, and all synchronization happens on it.

If you want to see the out of sync message, try removing the synchronized keyword. Then after some time you should see the expected out of sync message.

Sidenotes:

  • Because out of sync is a message, it should probably be printed on System.err, not System.out.
  • Instead of a.rand.nextInt(2) == 1, you could use a.rand.nextBoolean().
  • Having class B access field rand of class A breaks encapsulation, you might want to give class A a method randomBoolean() which does return rand.nextBoolean(), and call that method randomBoolean() from class B.
  • Having the same variable names with different meanings in different contexts may be confusing. In class A, the variables a and b denote two numbers, in other contexts, the variables a and b refer to instances of class A and class B. Consider renaming the fields of class A to something else, like number1 and number2.
Related