Issue
I was trying to understand more about Thread.interrupt(), and so I wrote the following codes.
public class Test {
private Object object = new Object();
Runnable thread1 = () -> {
synchronized (object) {
System.out.println(System.currentTimeMillis() + " - Thread1 inside synchronized block");
try {
object.wait();
System.out.println(System.currentTimeMillis() + " - Thread1 after wait()");
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(System.currentTimeMillis() + " - Thread1 ending");
}
};
Runnable thread2 = () -> {
synchronized (object) {
System.out.println(System.currentTimeMillis() + " - Thread2 inside synchronized block");
try {
Thread.sleep(2000);
System.out.println(System.currentTimeMillis() + " - Thread2 after sleep");
object.notify();
System.out.println(System.currentTimeMillis() + " - Thread2 after notify()");
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(System.currentTimeMillis() + " - Thread2 ending");
}
};
public void run() {
Thread t1 = new Thread(thread1);
Thread t2 = new Thread(thread2);
t1.start();
t2.start();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
t1.interrupt();
}
public static void main(String[] args) {
new Test().run();
}
}
I couldn't understand the result. Firstly, why is the exception stack trace not showing on the third line of the output? The first thread was interrupted while the second thread was still sleeping, so the exception should occur before the second thread woke up. Secondly, why is "Thread 1 ending" showing up before the stack trace?
1643099950931 - Thread1 inside synchronized block
1643099950947 - Thread2 inside synchronized block
1643099952947 - Thread2 after sleep
1643099952947 - Thread2 after notify()
1643099952947 - Thread2 ending
1643099952947 - Thread1 ending
java.lang.InterruptedException
at java.base/java.lang.Object.wait(Native Method)
at java.base/java.lang.Object.wait(Object.java:328)
at com.ocbc.ms.Test.lambda$new$0(Test.java:13)
at java.base/java.lang.Thread.run(Thread.java:834)
Solution
From the documentation of Thread.wait
(relevant part highlighted in bold):
Causes the current thread to wait until it is awakened, typically by being notified or interrupted, or until a certain amount of real time has elapsed.
...
This method causes the current thread (referred to here as T) to place itself in the wait set for this object and then to relinquish any and all synchronization claims on this object.
Thread T then becomes disabled for thread scheduling purposes and lies dormant until one of the following occurs:
...
Some other thread interrupts thread T.
...
The thread T is then removed from the wait set for this object and re-enabled for thread scheduling. It competes in the usual manner with other threads for the right to synchronize on the object; once it has regained control of the object, all its synchronization claims on the object are restored to the status quo ante - that is, to the situation as of the time that the wait method was invoked. Thread T then returns from the invocation of the wait method. Thus, on return from the wait method, the synchronization state of the object and of thread T is exactly as it was when the wait method was invoked.
In other words, when thread 1 is interrupted by the main thread, it still has to wait for thread 2 to finish to relinquish its lock, and only then thread 1 will regain control of the lock and continue.
Answered By - M A
Answer Checked By - Candace Johnson (JavaFixing Volunteer)