Going by the below code, I have two instances of class A - a1 and a2. And calling the method foo() on both the instances separately.
There is a synchronized block within the foo() method, which is locked on the calling object. Since it is an instance-level locking, both the methods should start executing at the same time because they are getting invoked from two separate instances. But, they are getting executed sequentially.
Is it because, both the instances getting invoked from the same Thread main?
Code changes: Made class A implements Runnable, renamed foo() to run(), forked a thread t from main, invoked a1.run() from main thread, invoked a2.run() from the thread t . Though the two A instances - a1 & a2 are getting called from two threads - main & thread t, the synchronized block(this) seems to be getting locked.
My understanding was the 'this' is referring to the calling Runnable instance which is different and even the threads are different. So, Thread.sleep should not make the other thread blocked. Then, why the two invocation of run's not happening in parallel?
Expected Output (should execute parallel)
main <time> Inside A.run
Thread-0 <time> Inside A.run
Thread-0 <time+4s> Exiting A.run
main <time+5s> Exiting A.run
Actual Output (executing sequentially)
main <time> Inside A.run
main <time+5s> Exiting A.run
Thread-0 <time+5s> Inside A.run
Thread-0 <time+9s> Exiting A.run
import java.time.*;
import java.time.format.DateTimeFormatter;
public class Test {
public static void main(String[] args) {
/*A a1 = new A(5000); A a2 = new A(4000);
a1.foo(); a2.foo();*/
A a1 = new A(5000); A a2 = new A(4000);
Thread t = new Thread(a2);
/*a1.run(); t.start();*/
t.start(); a1.run(); // <-- putting t.start() before a1.run() solves the issue
}
}
class A implements Runnable {
public long waitTime;
public A() {}
public A(long timeInMs) {
waitTime = timeInMs;
}
public void run() {
synchronized(this) {
try {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
LocalDateTime time = LocalDateTime.now();
System.out.println(Thread.currentThread().getName() + " " + formatter.format(time) + " Inside A.run");
Thread.sleep(waitTime);
time = LocalDateTime.now();
System.out.println(Thread.currentThread().getName() + " " + formatter.format(time) + " Exiting A.run");
} catch (InterruptedException e) {}
}
}
}
You started to run a1
synchronously before starting the thread, of course you will get a1's output on the main thread because it won't have been able to reach the thread start statement until a1 is finished.
Try starting the thread running a2
first before you run a1
on the main thread, see what you get.
You should also be aware that thread scheduling may be delayed, and calling Thread#start
does not immediately begin execution on a separate thread, but rather it queues it for the system thread scheduler. You might also want to consider using a synchronization device such as a CyclicBarrier
in order to coordinate between the thread running a2
and the main thread running a1
, else you may still get the exact same result even though it appears that you are starting the thread to run a1
before a2
.