Ninad Pingale
Ninad Pingale

Reputation: 7069

Synchronized thread method is executing concurrently - why?

I have one question about thread. I have following Thread class and creating 2 thread objects.

public class MyThread extends Thread{

    String name="";

    public MyThread(String string) {
        name=string;
    }    

    @Override
    public void run() {
        callMe();
    }       

    synchronized private void callMe() {
        System.out.println("Started");
        for (int i = 1; i <= 5; i++) {
            System.out.println(name+" = "+i);
        }           
    }


    public static void main(String[] args) {            
        MyThread a = new MyThread("A");
        MyThread b = new MyThread("B");

        a.start();
        b.start();
    }       
}

When I execute this , output I get is -

Started
Started
B = 1
B = 2
A = 1
A = 2
B = 3
A = 3
B = 4
A = 4
B = 5
A = 5

I know that A and B are printed randomly as Thread Scheduler picks it up.

But my question is: why loop is NOT executed one after other? I have used synchronized keyword.

Upvotes: 4

Views: 296

Answers (4)

Ironluca
Ironluca

Reputation: 3762

Because 2 threads are executing through 2 different objects.

All right, you must have by now realized from the other answers. You are creating 2 separate objects, viz. a and b. Now, when you call the start method, a new thread is started to execute through the run method of the respective (separate not same) objects. The synchronization is indeed on the method but there is exactly one thread running through the callMe method of a and exactly one thread running through callMe method of b. So your expectation that the output should be:

A - 1 A - 2 A - 3 ...

is not happening.

Hope this helps

Upvotes: 2

jontro
jontro

Reputation: 10628

Synchronized works per Object. To synchronize across instances you need a shared object to synchronize on.

I.e.

private final static Object globalLock = new Object();
// Later 
private void callMe() {
  synchronized (globalLock) {
    System.out.println("Started");
    for (int i = 1; i <= 5; i++) {
       System.out.println(name+" = "+i);
    }
  }
}

Upvotes: 9

KonDeichmann
KonDeichmann

Reputation: 968

Your Code is equal to this Code

 private void callMe(){
       synchronized(this){
           System.out.println("Started");
           for (int i = 1; i <= 5; i++) {
              System.out.println(name+" = "+i);
           }
       }                           
 }

You just synchronise to the current Object. If you want to synchronise them to each other your need to synchronise to the class, like this :

private void callMe(){
   synchronized(MyThread.class){
     System.out.println("Started");
     for (int i = 1; i <= 5; i++) {
          System.out.println(name+" = "+i);
     }
   }  
}                              

Upvotes: 3

Jon Skeet
Jon Skeet

Reputation: 1499760

Your synchronized method is effectively:

private void callMe() {
    synchronized(this) {
        System.out.println("Started");
        for (int i = 1; i <= 5; i++) {
            System.out.println(name+" = "+i);
        }
    }
}

Now you've created two different instances, so this will be different for each thread... so they're not synchronizing against each other. If you want to see two threads working with the same monitor, you could rewrite your code like this:

public final class DemoRunnable implements Runnable {
    @Override
    public synchronized void run() {
        System.out.println("Started");
        for (int i = 1; i <= 5; i++) {
            System.out.println(Thread.currentThread().getName() + " = " + i);
        }
    }

    public static void main(String[] args) {
        Runnable runnable = new DemoRunnable();
        Thread a = new Thread(runnable, "A");
        Thread b = new Thread(runnable, "B");
        a.start();
        b.start();
    }
}

Then you'll get output like this:

Started
A = 1
A = 2
A = 3
A = 4
A = 5
Started
B = 1
B = 2
B = 3
B = 4
B = 5

(Although it could be the other way round, of course.)

We still have two threads, but they're calling a synchronized method on the same object (a DemoRunnable in this case) so one will have to wait for the other to complete.

A few points:

  • Implementing Runnable is generally preferred over extending Thread; it's more flexible
  • Synchronizing on a Thread object has its own issues, as the Thread class does it itself; try to avoid it
  • Personally I don't like synchronizing on this anyway - I would usually have a private final variable of type Object to represent a monitor that only my code knows about... that way I can easily see all the code that could synchronize on it, which makes it easier to reason about

Upvotes: 13

Related Questions