Recently, I am handling the graceful shutdown of Syncer. In the process of implementation, I was surprised by some counterintuitive part of Java. Let’s go on and see whether you know it.
Thread States
The following enumerations are states of Java Thread
which is cited from Java documentation:
NEW
A thread that has not yet started is in this state.RUNNABLE
A thread executing in the Java virtual machine is in this state.BLOCKED
A thread that is blocked waiting for a monitor lock is in this state.WAITING
A thread that is waiting indefinitely for another thread to perform a particular action is in this state.TIMED_WAITING
A thread that is waiting for another thread to perform an action for up to a specified waiting time is in this state.TERMINATED
A thread that has exited is in this state.
The naming of state is fine, but those description is not clear enough though:
- What a
Thread
's state if it blocked inIO
operation? - What a
Thread
's state if it calledsleep
,wait
? - What a
Thread
's state if it is waiting to enterSynchronized
method/block? - What a
Thread
's state if it is waiting to gain aLock
?
In order to understand the differences between them better, we use run some examples to see:
public static void main(String[] args) throws InterruptedException {
test(States::getSleep);
test(States::getWait);
test(States::getIO);
// ...
}
private static void test(Supplier<Runnable> supplier) throws InterruptedException {
System.out.println("-------");
Thread thread = new Thread(supplier.get());
System.out.println(thread.getState());
thread.start();
Thread.sleep(1000);
System.out.println(thread.getState());
Thread.sleep(1000);
System.out.println(thread.getState());
thread.interrupt();
System.out.println(thread.getState());
System.out.println("-------");
}
private static Runnable getSleep() {
return () -> {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
};
}
private static Runnable getIO() { }
private static Runnable getWait() { }
From the output, we can answer above answer:
- A thread blocking in IO is
RUNNABLE
; - A thread in
sleep()
isTIMED_WAITING
; - A thread n
wait()
isWAITING
, inwait(long timeout)
isTIMED_WAITING
; - A thread waiting for
Synchronized
isBLOCKED
; - A thread waiting for
lock
isWAITING
, inlockInterruptibly
isTIMED_WAITING
;
If you have doubt about the state of thread in other state, just write some examples to verify you guess. oow o Interrupt
Understand the state of states, we are going to see how to interrupt them when they are in different states. If thread in NEW
or TERMINATED
, we don’t need to interrupt them, so we only focus on th oher s.
The interrupt mechanism in Java is just a flag in thread object, so if thread is RUNNABLE
and doesn’t check thread status, it will just continue to run. For example, if we have a while loop to do some calculation and not check interrupt flag, it will just continue; If our code block in IO, interrupt may be work. There is an exception called java.io.InterruptedIOException
, which is supposed to cover the situation where you interrupt a thread that is waiting o s I octe However, the reality is that it is only implemented by a few IO operation in a few class like PipedReader
.
Threads can be WAITING/TIMED_WAITING
on wait()
s,
tanlb oth thr a nterruptctio when the flag of thread is set.
We ot ut a thread in otr a ynhronized if we e o ordead obe e to twn otdsryst leay. But if we called Lock#lockInterruptibly
, we can interrupt it.
In order to set the interrupt flag of thread, we can:
- call
Thread#interrup()
; - call
Future#cancel(true)
shutdownNow(..)
method on yourExecutorService
Shutdown ShutdownNow
The first thing make us surprised is the differences between Shutdown
and ShutdownNow
:
shutdown()
will just tell the executor service that it can’t accept new tasks, but the already submitted tasks continue to runshutdownNow()
will do the same AND will try to cancel the already submitted tasks by interrupting the relevant threads. Note that if our tasks ignore the interruption,shutdownNow
will behave exactly the same way asshutdown
.
Ctrl-C?
Another counter-intuitive things is JVM
will not send signal from OS to Java
's thread, i.e. JVM will just shutdown and not set interrupt flag for threads or throw InterruptException
.
signal 2: SIGINT
signal 9: SIGKILL
Even though JVM
do nothing for Ctrl-C
, it has a Ctrl-Break handler to do thread dump.
How to Handle Interrupt
For a clean shutdown of thread, we should not swallow InterruptedException
:
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
Thread.currentThread().interrupt(); // re-interrupt or re-throw
throw new RuntimeException(ex);
}
or loop with thread state
while (!Thread.interrupted()) {
// event handle
}
Ref
Written with StackEdit.
评论
发表评论