Java

Synchronizing using method local variables versus the current instance “this”

There was one query which came up on Javaranch– it was related to difference between using synchronized block with a method local variable and current instance “this”. I thought that this would better be explained with a code and I came up with the following example code-

[java]
class MyThread implements Runnable
{
int i=0;
int j=0;
public void run()
{
String[] myArgs = new String[]{"item1","item2"};
myMethod1(myArgs);
myMethod2();
}
public void myMethod1(String[] args)
{
synchronized(args)
{
i=i+1;
System.out.println("In myMethod1 "+i);
i=i+1;
}
}
public void myMethod2()
{
synchronized(this)
{
j=j+1;
System.out.println("In myMethod2 "+j);
j=j+1;
}
}
}
[/java]

This class MyThread has two methods- myMethod1 which is synchronized using the local variable “args” and myMethod2 which is synchronized using the “this” reference variable. Now lets create a Thread of execution and see what happens:

[java]
public class MyThreadTester
{
public static void main(String[] args)
{
MyThread mt = new MyThread();
Thread myT = new Thread(mt);
Thread myT2 = new Thread(mt);
myT.start();
myT2.start();
}
}
[/java]

In the above piece of code- Am creating two threads- myT and myT2- both of which are executing the same piece of code provided my the MyThread class. Actually our desired output would be-
Desired output- (order of printing not important)
In myMethod1 1
In myMethod2 1
In myMethod1 3
In myMethod2 3

myMethod1 and myMethod2 are incrementing 2 different variables- i and j respectively. So it would be expected to that each of them prints 1 and 3 as the values. But after executing the above code, the following is one of the outputs:(one-of the because, order of execution of the threads is not guaranteed and also due to a flaw in synchronization)-
Output:
In myMethod1 1
In myMethod2 1
In myMethod1 2
In myMethod2 3

One can see that though myMethod2 is printing the desired values-1 and 3. But myMethod1 is not. If we analyse the outputs we can conclude that the 2 statements- increment, print, increment are not atomic. That is because in myMethod1 these statements are synchronized using a method local variable which means that each method executing will have its own local copy of the variable and thus it can get the lock and enter the synchronized block (Race condition is still happening). Thats not the case with myMethod2. In myMethod2 the block is synchronized on “this” reference variable which means that if the same instance is used to execute the thread code- only one thread can enter the synchronized block. You can see that same instance of MyThread is being used by both the threads- myT and myT2. So lets change the class MyThread by synchronizing both the methods using the “this” reference variable.

[java]
class MyThread implements Runnable
{
int i=0;
int j=0;
public void run()
{
String[] myArgs = new String[]{"item1","item2"};
myMethod1(myArgs);
myMethod2();
}
public void myMethod1(String[] args)
{
synchronized(this)
{
i=i+1;
System.out.println("In myMethod1 "+i);
i=i+1;
}
}
public void myMethod2()
{
synchronized(this)
{
j=j+1;
System.out.println("In myMethod2 "+j);
j=j+1;
}
}
}
[/java]

So if we now try to execute the program, lets look at the output:(order of printing isn’t important)
Output:
In myMethod1 1
In myMethod1 3
In myMethod2 1
In myMethod2 3

One can see that- both the methods prints- 1 and 3 as the output for i and j. You could try to execute it multiple times and even then you can get the same value for i and j. It is because the three statements- increment, print, increment have been made atomic by synchronizing on “this” reference variable.

Summarizing the difference: The method local variables synchronize the block for one thread access only. Suppose if there are multiple threads executing the same method- this synchronization fails cause each method will have its copy of the lock. Where as, synchronizing on “this” reference variable will be fine as long as different threads are executing the same runnable code- in other words, the same instance of Runnable code. Again if we have multiple instances of the runnable code and each thread has its own instance of code- In that case even “this” fails to synchronize.

Advertisements

Categories: Java

Tagged as: , , ,

3 replies »

  1. Hi,
    It is easy to undserstand.Could you tell me how to write same this type of programming using extends Thread class.I tried but i got race condition in the both methods.

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s