Do you read Heinz Kabutz's newsletter? I do, even though I don't always understand what a Java Champion such as Heinz means. :-) As I 'm not a Java champion and I don't think I 'll ever be, I sometimes spend quite a lot of time to follow Java champions' newsletters, speeches etc. :-)
This happened with his issue 146, "Secrets of Concurrency (Part 1) -- The Law of the Ritalin Child". To understand this newsletter, on a difficult topic such as threads, I had to create some drawings on a piece of paper. So, for all the rest of you who didn't understand exactly what that issue says, or who didn't bother to look more seriously into it, here I put a drawing and my understanding of it.
This happened with his issue 146, "Secrets of Concurrency (Part 1) -- The Law of the Ritalin Child". To understand this newsletter, on a difficult topic such as threads, I had to create some drawings on a piece of paper. So, for all the rest of you who didn't understand exactly what that issue says, or who didn't bother to look more seriously into it, here I put a drawing and my understanding of it.
So, back to our subject. The first question Heinz poses in his newsletter is what does
Let's first examine when an
InterruptedException
mean?Let's first examine when an
InterruptedException
is thrown. A thread can be in any one of the states that are shown in the following state transition diagram, i.e. NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING
and TERMINATED
. See java.lang.Thread.State if you don't believe me.Now, assume that our thread, lets call it
"[i]f the thread is not in a waiting state, then only the interrupted status is set, nothing else."
I.e., if
thisThread
, is in the RUNNABLE
state. Heinz says that"[i]f the thread is not in a waiting state, then only the interrupted status is set, nothing else."
I.e., if
thisThread
's state is RUNNABLE
, and it calls its interrupt()
method, the only thing that happens is that thisThread.interrupted=true
. In other words:// thisThread is in RUNNABLE state
// when
thisThread.interrupt();
then the following occurs:thisThread.interrupted=true;
"If the thread is currently in either the WAITING or TIMED_WAITING states, it immediately causes an InterruptedException and returns from the method that caused the waiting state."
I.e., if
I.e., if
thisThread
's state is either WAITING
or TIMED_WAITING
, and its interrupt()
method is called,
it throws an InterruptedException
and returns from the method that caused the waiting state. Its interrupted
status should already be true
. However, as we shall see later, when an InterruptedException
is thrown, the interrupted
status of the thread is flipped back to false
. In other words://
thisThread
is in WAITING or TIMED_WAITING
state// when
thisThread.interrupt();
then an
InterruptedException
is thrown andthisThread.interrupted=false;
"However, if later on the thread calls a method that would change the state into WAITING or TIMED_WAITING, the InterruptedException is immediately caused and the method returns."
I.e. if
I.e. if
thisThread.interrupted=true
, because its interrupt()
method was called previously, and thisThread
called a method that causes a state transition to one of either WAITING
or TIMED_WAITING
states, then, because thisThread.interrupted
is already true
, an InterruptedException
is immediately thrown and its state remains to RUNNABLE
. In other words:// thisThread is in RUNNABLE state
thisThread.interrupted=true;
// when
thisThread.wait();
then
thisThread.State=RUNNABLE
an
InterruptedException
is thrown andthisThread.interrupted=false;
But how can
thisThread
change its state to WAITING or TIMED_WAITING
? By calling one of the following methods: wait(), Thread.sleep(), BlockingQueue.get(), Semaphore.acquire()
and Thread.join()
.E.g.
try {
Thread.sleep(1000); // 1 second
} catch(InterruptedException ex) {
// ignore - won't happen
}
"Note that attempting to lock on a monitor with
OK? Did you get that? If
The interrupted status is nowadays commonly used to indicate when a thread should be shut down because it is thrown at well defined places that wouldn't cause any problems, not like
"Note that the interrupted status is set to false when an InterruptedException is caused or when the
So, what should we do when we call code that may cause an InterruptedException? Heinz has two answers on this:
synchronized
puts the thread in BLOCKED state, not in WAITING nor TIMED_WAITING. Interrupting a thread that is blocked will do nothing except set the interrupted status to true. You cannot stop a thread from being blocked by interrupting it. Calling the stop()
method similarly has no effect when a thread is blocked. "OK? Did you get that? If
thisThread.State=BLOCKED
, calling its interrupt()
method, simply causes thisThread.interrupted=true
while calling its stop()
method has no effect.The interrupted status is nowadays commonly used to indicate when a thread should be shut down because it is thrown at well defined places that wouldn't cause any problems, not like
Thread.stop()
method. The problem with the Thread.stop()
method was that it would cause an asynchronous exception at any point of the thread's execution code."Note that the interrupted status is set to false when an InterruptedException is caused or when the
Thread.interrupted()
method is explicitly called. Thus, when we catch an InterruptedException, we need to remember that the thread is now not interrupted anymore! In order to have orderly shutdown of the thread, we should keep the thread set to "interrupted"."So, what should we do when we call code that may cause an InterruptedException? Heinz has two answers on this:
- Rethrow the InterruptedException from your method.
- Catch it, set interrupted status, return
while (!Thread.currentThread().isInterrupted()) {
// do something
try {
TimeUnit.SECONDS.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
Remember! Don't just ignore interruptions, deal with the cause!
So, to recap:
So, to recap:
- if a thread is in
RUNNABLE
state and itsinterrupt()
method is called, itsinterrupted
status changes totrue
; - if a thread is in
WAITING
orTIMED_WAITING
state and itsinterrupt()
method is called, it throws anInterruptedException
and itsinterrupted
status changes back tofalse
; - if a thread is in
RUNNABLE
state and one of its methods that changes its state toWAITING
orTIMED_WAITING
is called, and, previously itsinterrupted
status has been set totrue
by a call to itsinterrupt()
method, then anInterruptedException
is thrown, its state changes toRUNNABLE
and its
interrupted
status changes back tofalse
; - finally, if a thread is in
BLOCKED
state and itsinterrupt()
method is called, itsinterrupted
status changes totrue
; while nothing seems to happen when itsstop()
method is called. (It seems that if there is a lot of contention for locks, the stop signals get lost).
public class CheckBlocking {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread() {
public void run() {
while (true) {
System.out.println("t1");
synchronized (CheckBlocking.class) {
try {
CheckBlocking.class.wait(10000);
} catch (InterruptedException e) {
interrupt();
return;
}
}
}
}
};
Thread t2 = new Thread() {
public void run() {
while (true) {
System.out.println("t2 blocked");
synchronized (CheckBlocking.class) {
System.out.println("t2");
try {
CheckBlocking.class.wait(950);
} catch (InterruptedException e) {
interrupt();
return;
}
}
}
}
};
t1.start();
Thread.sleep(2000);
t2.start();
Thread.sleep(2000);
t2.stop();
}
}
If you run this code, you will notice that no exception is thrown. It gets lost somewhere.
Thanks Heinz.
Thanks Heinz.
For those of you who want to learn about Java threads, I would recommend "Java concurrency in practice" by Brian Goetz, Tim Peierls, Joshua Bloch, Joseph Bowbeer, David Holmes, Doug Lea, the only book in my opinion that explains in plain english and allows you to understand what is going on in multithreading java and the strange behaviour of your multithreading programs, if you have encountered such.
Δεν υπάρχουν σχόλια:
Δημοσίευση σχολίου