Reputation: 19
I am learning multi threading. I've written a program using synchronization to print table of 10 and 5 using two threads. While synchronized method is giving me expected result, synchronized block isn't. What am i doing wrong?
public class SynchronizationDemo {
public static void main(String[] args) {
Thread1 t=new Thread1(10);
Thread1 t1=new Thread1(5);
Thread thread1=new Thread(t);
Thread thread2=new Thread(t1);
thread1.start();
thread2.start();
}
//synchronized method
/*public static synchronized void printTable(int num) {
for (int i = 1; i <= 10; i++) {
System.out.println(num*i);
try {
Thread.sleep(1000);
}catch(InterruptedException ie){
ie.printStackTrace();
}
}
}*/
//synchronized block
public void printTable(int num)
{
synchronized(this){
for (int i = 1; i <= 10; i++) {
System.out.println(num*i);
try {
Thread.sleep(1000);
}catch(InterruptedException ie){
ie.printStackTrace();
}
}
}
}
}
class Thread1 implements Runnable{
int num;
Thread1(int num){
this.num=num;
}
@Override
public void run() {
new SynchronizationDemo().printTable(num);
}
}
Output of the code : 10 5 10 20 30 15 20 40 25 50 60 30 70 35 40 80 90 45 100 50
Expected output: 10 20 30 40 50 60 70 80 90 100 5 10 15 20 25 30 35 40 45 50
Upvotes: 1
Views: 69
Reputation: 3938
You are using synchronized
keyword in two different contexts.
static synchronized
method waits & gets a lock at SynchronizationDemo class level and there is only one lock for that class. So all the instances of that class will have to wait for that lock in a sequence.
synchronized(this)
block (or even a method) waits and gets a lock of objects of SynchronizationDemo class and there is a lock per each object. As each run() method creates its own instance new SynchronizationDemo()
, that method does not need to wait until other methods are completed.
Try changing your Thread1 class by passing an object.
class Thread1 implements Runnable{
SynchronizationDemo demo;
int num;
Thread1(SynchronizationDemo demo, int num){
this.demo = demo;
this.num = num;
}
@Override
public void run() {
demo.printTable(num);
}
}
Now, you can pass the same object of SynchronizationDemo class to both threads as below.
public static void main(String[] args) {
SynchronizationDemo demo = new SynchronizationDemo();
Thread1 t=new Thread1(demo, 10);
Thread1 t1=new Thread1(demo, 5);
Thread thread1=new Thread(t);
Thread thread2=new Thread(t1);
thread1.start();
thread2.start();
}
Upvotes: 1
Reputation: 262842
The difference is that you also changed the method to no longer be static
.
public static synchronized void printTable(int num) { }
This locks on the class, not on any single instance.
The equivalent synchronized block would be
synchronized(SynchronizationDemo.class){
}
So even if you have two instances, they are still using the same lock (because they are both of the same class), whereas a synchronized(this)
locks on two independent objects.
Upvotes: 0
Reputation: 2147
You are creating new instance of SynchronizationDemo
's object in run()
method of thread.
@Override
public void run() {
new SynchronizationDemo().printTable(num);
}
So each thread has a new object. So in SynchronizationDemo.class
synchronized blocks are useless if two or more thread not access to same object. Because of that threads works different object and each thread print out its number.
Run your code 2 or more times , you can see the different output , if thread1
works earlier than thread2
or not.
You should use static synchronized
keyword with printTable
method ;
public static synchronized void printTable(int num){
//do sth.
}
Upvotes: 0
Reputation: 719679
The main difference between the two approaches is in a small but important detail.
Your synchronized block is synchronizing on this
.
Your synchronized method (the commented out one!) is a static
method. That means that it is synchronizing on the SynchronizationDemo
class object!!
But that doesn't explain it all. The other thing is the way that you are calling the method.
new SynchronizationDemo().printTable(num);
You are creating a new instance and then calling the method on it.
When you call the static method, it makes no difference which instance you use ... because you are synchronizing on the Class
object.
When you call the instance method, the instances are different, and therefore there is no mutual exclusion at all. You only get mutual exclusion and proper synchronization when the two threads synchronize on the same object.
Upvotes: 4