跳至主要内容

Interrupt Thread

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 in IO operation?
  • What a Thread's state if it called sleep, wait?
  • What a Thread's state if it is waiting to enter Synchronized method/block?
  • What a Thread's state if it is waiting to gain a Lock?

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() is TIMED_WAITING;
  • A thread n wait() is WAITING, in wait(long timeout) is TIMED_WAITING;
  • A thread waiting for Synchronized is BLOCKED;
  • A thread waiting for lock is WAITING, in lockInterruptibly is TIMED_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 your ExecutorService

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 run
  • shutdownNow() 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 as shutdown.

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.

评论

此博客中的热门博文

Spring Boot: Customize Environment

Spring Boot: Customize Environment Environment variable is a very commonly used feature in daily programming: used in init script used in startup configuration used by logging etc In Spring Boot, all environment variables are a part of properties in Spring context and managed by Environment abstraction. Because Spring Boot can handle the parse of configuration files, when we want to implement a project which uses yml file as a separate config file, we choose the Spring Boot. The following is the problems we met when we implementing the parse of yml file and it is recorded for future reader. Bind to Class Property values can be injected directly into your beans using the @Value annotation, accessed via Spring’s Environment abstraction or bound to structured objects via @ConfigurationProperties. As the document says, there exists three ways to access properties in *.properties or *.yml : @Value : access single value Environment : can access multi...

Elasticsearch: Join and SubQuery

Elasticsearch: Join and SubQuery Tony was bothered by the recent change of search engine requirement: they want the functionality of SQL-like join in Elasticsearch! “They are crazy! How can they think like that. Didn’t they understand that Elasticsearch is kind-of NoSQL 1 in which every index should be independent and self-contained? In this way, every index can work independently and scale as they like without considering other indexes, so the performance can boost. Following this design principle, Elasticsearch has little related supports.” Tony thought, after listening their requirements. Leader notice tony’s unwillingness and said, “Maybe it is hard to do, but the requirement is reasonable. We need to search person by his friends, didn’t we? What’s more, the harder to implement, the more you can learn from it, right?” Tony thought leader’s word does make sense so he set out to do the related implementations Application-Side Join “The first implementation ...

Learn Spring Expression Language

When reading the source code of some Spring based projects, we can see some code like following: @Value( "${env}" ) private int value ; and like following: @Autowired public void configure (MovieFinder movieFinder, @ Value ("#{ systemProperties[ 'user.region' ] } ") String defaultLocale) { this.movieFinder = movieFinder; this.defaultLocale = defaultLocale; } In this way, we can inject values from different sources very conveniently, and this is the features of Spring EL. What is Spring EL? How to use this handy feature to assist our developments? Today, we are going to learn some basics of Spring EL. Features The full name of Spring EL is Spring Expression Language, which exists in form of Java string and evaluated by Spring. It supports many syntax, from simple property access to complex safe navigation – method invocation when object is not null. And the following is the feature list from Spring EL document : ...