Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 853
Ninad Pingale Avatar asked Nov 28 '22 16:11

Ninad Pingale


1 Answers

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
like image 199
Jon Skeet Avatar answered Dec 03 '22 20:12

Jon Skeet