A detailed explanation of interrupt handling in Java programming _java

Source: Internet
Author: User
Tags thread class

1. Introduction

When we click on the cancellation button of an antivirus software to stop the virus, when we typed the Quit command at the console to end a background service ... Requires a thread to cancel a task that another thread is performing. Java does not provide a safe and straightforward way to stop a thread, but Java provides an interrupt mechanism.

If you do not have a comprehensive understanding of Java interrupts, you may mistakenly assume that the interrupted thread will immediately quit running, but that is not the case. How does the interrupt mechanism work? After the interrupt is captured or detected, what is the consequence of throwing a interruptedexception or resetting the interrupt state and swallowing the interrupt state in the method? What are the similarities and differences between thread.stop and interruptions? Under what circumstances do I need to use interrupts? This article will be described from several aspects.

2. Principle of interruption

The Java interrupt mechanism is a collaborative mechanism that means that interrupts do not terminate directly from another thread, and that threads that need to be interrupted handle interrupts themselves. This is like home parents told children to pay attention to the body, but whether the children pay attention to the body, how to pay attention to the body depends entirely on their own.

The Java interrupt model is also so simple that each thread object has a Boolean identifier (not necessarily the field of the thread class, and indeed not, these methods are ultimately done through the native method), Represents an interrupt request (the request can come from all threads, including the interrupted thread itself). For example, when a thread T1 to the thread T2, you only need to set the interrupt identity of the threading T2 object to True in thread T1, and 2 can choose to handle the interrupt request at the right time, even ignoring the request, as if the thread had not been interrupted.

The Java.lang.Thread class provides several ways to manipulate this interrupt state, including:

public static booleaninterrupted

Test if the thread has been interrupted. The interrupt state of the thread is cleared by the method. In other words, if the method is called twice in a row, the second call returns FALSE, except if the first call has cleared its break state, and the second call is interrupted before the interrupt state is checked out.

Public booleanisinterrupted ()

Whether the test thread has been interrupted. The interrupt state of a thread is not affected by this method.

public void Interrupt ()

The thread is disconnected.
Where the interrupt method is the only way to set the interrupt state to true. The static method interrupted the current thread's interrupt state, but the method's naming is highly intuitive and easily misleading, requiring special attention.

In the above example, the thread T1 the interrupt state of the thread T2 to TRUE,T2 by calling the interrupt method, which can be invoked at the appropriate time interrupted or isinterrupted to detect the state and do the appropriate processing.

In addition, the methods of some classes in the class library may call interrupts, such as the Cancel method in Futuretask, and if the passed argument is true, it will call the interrupt method on the thread that is running the asynchronous task. If the code in the asynchronous task being executed does not respond to the interrupt, then the parameters in the Cancel method will not be effective , and the Shutdownnow method in Threadpoolexecutor loops through the worker threads in the thread pool and calls the thread's interrupt method to break threads, so if the task being performed in the worker thread does not respond to the interrupt, the task will continue until the normal end.

3. Interruption of processing

Since the Java interrupt mechanism simply sets the interrupt state of the interrupted thread, what does the interrupted thread do?

Processing time

Obviously, as a collaborative mechanism, the interrupted thread is not forced to be processed at a certain point. In fact, the interrupted thread only needs to be handled at the right time, if there is no proper point of view, or even if it is not handled, at the task-handling level, just like without calling the interrupt method. The "Right time" is closely related to the business logic of the line one thread in processing, for example, each iteration is preceded by a method that may be blocked and cannot be interrupted, but most often does not occur when a critical section updates another object's state, as this can cause the object to be in an inconsistent state.

The processing time determines the efficiency of the program and the sensitivity of the interrupt response. Frequent checking of interrupt status may cause program execution to degrade, and conversely, fewer checks may make interrupting requests less responsive. If the interrupted thread continues to perform a period of time without causing a disaster to the system after the interrupt request is issued, the interrupt processing can be placed where it is convenient to check for interruptions while at the same time ensuring a certain degree of responsiveness. When the performance index of the program is more critical, it may be necessary to set up a test model to analyze the best interrupt detection point to balance performance and response sensitivity.

It is dangerous for a thread to terminate before it is properly terminated. Because it can bring serious consequences that are completely unexpected. So you see Thread.Suspend, Thread.stop and other methods are deprecated.
then it is not possible to hang a thread directly, but sometimes it is necessary to let a thread die, or let it end some kind of waiting state? The elegant approach is to give that thread an interrupt signal and let it decide what to do. For example, in a child thread, in order to wait for certain conditions to come, You call Thread.Sleep (10000) and expect the thread to wake up after 10 seconds of sleep, but if this particular condition arrives in advance, how do you inform a sleeping thread? For example, the main thread blocks itself to wait for the child thread to end by calling the join method of the child thread, but when the child thread runs, it finds itself in a short period of time, so it needs to find a way to tell the main line Cheng waiting for me. In these cases, you need to break.
interrupts are done by calling the Thread.Interrupt () method. This method informs the thread by modifying the interrupt state of the invoked thread, saying that it was interrupted. For threads that are not blocked, only the interrupt state is changed, that is, the thread.isinterrupted () returns true; For threads in a blocking state that can be canceled, such as the thread waiting on these functions, Thread.Sleep (), object.wait (), Thread.Join (), the thread receives the interrupt signal and throws interruptedexception. It also resets the interrupt state back to false.
The following program shows interrupts for threads in non-blocking:

public class Thread3 extends thread{public
  void Run () {while
    (true) {
      if (thread.interrupted ()) {
        System.out.println ("Someone interrupted me.");
      }
      else{
        System.out.println ("Going ...");
      }
      Long now = System.currenttimemillis ();
      while (System.currenttimemillis ()-now<1000) {
        //To avoid the confusion of understanding caused by thread.sleep () and the need to capture interruptedexception,
        //Here idling for 1 seconds
  
  }} public static void Main (string[] args) throws interruptedexception {
    Thread3 t = new Thread3 ();
    T.start ();
    Thread.Sleep (3000);
    T.interrupt ();
  }

The following program demonstrates that the child thread notifies the parent line Cheng and so on:

public class Thread4 extends thread {
  private thread parent;
  Public Thread4 (Thread parent) {
    this.parent = parent;
  }
  
  public void Run () {while
    (true) {
      System.out.println (' Sub thread is running ... ');
      Long now = System.currenttimemillis ();
      while (System.currenttimemillis ()-now <) {
        //To avoid thread.sleep () and the need to capture the interruptedexception caused by the confusion of understanding,
        //Here idling for 2 seconds in this way
      }
      Parent.interrupt ();
    }
  
  public static void Main (string[] args) {
    Thread4 t = new Thread4 (Thread.CurrentThread ());
    T.start ();
    try {
      t.join ();
    } catch (Interruptedexception e) {
      System.out.println ("Parent thread would die ...");
    }
  }
}

The interrupt state can be read by thread.isinterrupted () and can be read and cleared by a static method named Thread.interrupted (that is, the break state becomes false when the method is called).
It is sometimes disadvantageous to throw a exception after a blocked thread is interrupted and put the interrupt state back, because the interrupt state may be judged by another thread, so the safe way is to reset the state at the place where the exception is handled:

Boolean interrupted = false;
try {while
  (true) {
    try {return
      blockingqueue.take ();
    } catch (Interruptedexception e) {
      interrupted = true;
    }
  }
Finally {
  if (interrupted) {
    thread.currentthread (). interrupt ();
  }
}

When you need to throw a interruptedexception in the code call, you can choose to reset the interrupt state, or you can choose to throw the interruptedexception outside, which is determined by the outer caller.
Not all blocking methods can cancel the blocking state after receiving interrupts, and the input and output stream classes block waiting for I/O completion, but they do not throw interruptedexception, and they do not exit the blocking state if they are interrupted.
An attempt to acquire an internal lock (into a synchronized block) cannot be interrupted, but Reentrantlock supports interruptible acquisition patterns, namely Trylock (long time, Timeunit unit).

Treatment mode

(1), the management of the Interruption state

Generally, throwing interruptedexception in a potentially blocked method declaration implies that the method is interruptible, such as Blockingqueue#put, Blockingqueue#take, object#wait, thread# Sleep and so on, what should the interrupt information do if the program captures the interruptedexception that the interruptible blocking method throws or detects the interrupt? The following two general principles are generally available:

If you encounter an interruptible blocking method that throws a interruptedexception, you can continue to throw the exception to the upper layer of the method call stack and, if the interrupt is detected, you can clear the interrupt state and throw interruptedexception. Make the current method an interruptible method as well.
If sometimes it is not convenient to throw interruptedexception on the method, such as the method signature on an interface to implement no throws Interruptedexception, You can then capture the interruptedexception of an interruptible method and reset the interrupt state by Thread.currentThread.interrupt (). This is also true if the interrupt state is detected and cleared.
In general code, especially as a base class library, should never swallow interrupts, that is, after capturing the interruptedexception in the catch after nothing to do, clear the state of interruption without resetting the interrupt state also do not throw interruptedexception and so on. Because swallowing the interrupt state can cause the upper layer of the method call stack to not get this information.

Of course, when there is always an exception, when you are fully aware of who is calling your method, and the caller is not going to get into trouble because the interruption is swallowed up, you can do so.

In a way, it's about letting the upper layer of the method call stack know that the interrupt occurred. Suppose you write a class library, the class library has a method Amethod, detects and clears the interrupt state in the Amethod, but does not throw the interruptedexception, as the Amethod user, he does not know inside the detail, If a user uses interrupts to do something after calling Amethod, he will never detect interruptions after calling Amethod, because the interrupt information has been removed by Amethod. If as a user, encounter such a problematic class library, and can not modify the code, then how to deal with? You have to set up your own interrupt state in your class, and when you call the interrupt method, set that state at the same time, this is really no way to use the method.

(2), interrupted response

How do you respond when you find interrupts in your program? This depends on the actual situation. Some programs may terminate the thread as soon as they detect an interruption, some may be exiting the currently executing task, and continue to perform the next task ... As a collaborative mechanism, this should be negotiated with the interrupt side, when the call interrupt what will happen is known in advance, such as doing some transaction rollback operations, some clean-up work, some compensation operations. If you are unsure what response the thread will make after calling the interrupt of a thread, you should not interrupt the thread.

4. Thread.Interrupt VS Thread.stop

The Thread.stop method has not been recommended for use. In some respects, there are similarities between thread.stop and interrupt mechanism. When a thread is waiting for a built-in lock or IO, the stop will not abort the operation, and the program can continue to execute when the catch stops the exception, even though the stop is meant to stop the thread, which makes the program's behavior even more confusing.

So where are their differences? The most important thing is that the interrupt requires the program to detect and then do the appropriate processing, and thread.stop will be directly in the execution of the code throws Threaddeath error, this is a java.lang.Error subclass.

Before continuing, let's look at a small example:

Package com.ticmy.interrupt;
Import Java.util.Arrays;
Import Java.util.Random;
Import Java.util.concurrent.TimeUnit;
 public class Teststop {private static final int[] array = new int[80000];
  private static final Thread t = new Thread () {public void run () {try {System.out.println (sort (array));
  catch (Error err) {err.printstacktrace ();
 } System.out.println ("in thread T");
 
 }
 };
 static {Random Random = new Random ();
 for (int i = 0; i < Array.Length i++) {Array[i] = Random.nextint (i + 1); } private static int sort (int[] array) {for (int i = 0; i < array.length-1; i++) {for (int j = 0; J < array . length-i-1;
   J + +) {if (Array[j] < Array[j + 1]) {int temp = array[j];
   ARRAY[J] = array[j + 1];
  Array[j + 1] = temp;
 }} return array[0];
 public static void Main (string[] args) throws Exception {T.start ();
 TimeUnit.SECONDS.sleep (1);
 System.out.println ("Go to stop thread T");
 T.stop (); System.out.println ("Finish MaIn ");

 }
}

This example is very simple, thread t inside do a very time-consuming sorting operations, in the sorting method, only simple addition, subtraction, assignment, comparison and other operations, a possible implementation of the results are as follows:

 
Go to stop thread T
java.lang.ThreadDeath at
 java.lang.Thread.stop (thread.java:758)
 at Com.ticmy.interrupt.TestStop.main (teststop.java:44)
finish main in
thread T

The sort method here is a very time-consuming operation, which means that thread t is still executing the sort method when the main thread sleeps for a second and calls stop. It is such an easy way to throw mistakes! In other words, when you call stop, most Java bytecode can throw errors, even simple additions!

If the thread is currently holding a lock, the lock is released after the stop. Because this error can occur in a number of places, this makes it impossible for programmers to keep the object state from being inconsistent. For example, object obj holds a range value: The minimum value is low, the maximum is high, and the low is not greater than high, which is protected by lock locks to avoid a race condition when concurrency occurs and causes the relationship to fail. Assuming that the current low value is the 5,high value is 10, when the thread T gets lock, the low value is updated to 15, which is really bad, if the Error,low value of the stop is not captured 15,high or 10, This leads to a less than guaranteed relationship between them, which means that the object state is corrupted! If you catch the error caused by the stop when you assign a value to low, you may continue to assign the high variable, but who doesn't know which statement the error will throw if the relationship between the object states is more complicated? This approach is almost impossible to maintain, too complex! In the event of an interruption, it will not throw an error when performing a low assignment, so that the program is controllable for object state consistency.

The stop is disabled because it can cause inconsistent object status.

5. Use of interrupts

In general, there are several usage scenarios for interrupts:

Click the Cancel button in a desktop application;
An operation exceeds a certain execution time limit when it needs to be aborted;
Multiple threads do the same thing, as long as one thread succeeds and other threads can be canceled;
One or more errors in a set of threads cause the whole group to fail;
When an application or service needs to be stopped.
Let's look at a concrete example. In this example, the GUI is intended to be used, but given the complexity of the GUI code, the console is used to simulate the core logic. Here is a new disk file Scan task, scanning a directory of all the files and print the file path to the console, the scanning process may be very long. If you need to abort the task, simply type quit in the console and enter.

Package com.ticmy.interrupt;
Import Java.io.BufferedReader;
Import Java.io.File;

Import Java.io.InputStreamReader; public class Filescanner {private static void ListFile (File f) throws interruptedexception {if (f = = null) {throw NE
 W IllegalArgumentException ();
  } if (F.isfile ()) {System.out.println (f);
 Return
 } file[] Allfiles = F.listfiles ();
 if (thread.interrupted ()) {throw new Interruptedexception ("File Scan task is interrupted");
 The for (file file:allfiles) {//can also place interrupt detection here listfile (file); The public static String Readfromconsole () {BufferedReader reader = new BufferedReader (new InputStreamReader (System).
 in));
 try {return reader.readline ();
  catch (Exception e) {e.printstacktrace ();
 Return ""; } public static void Main (string[] args) throws Exception {final thread fileiteratorthread = new Thread () {Publ
  IC void Run () {try {listfile (new File ("c:\\"));
  catch (Interruptedexception e) {e.printstacktrace ();
 }
  }
 }; New Thread () {PUBlic void Run () {while (true) {if ("Quit". Equalsignorecase (Readfromconsole ())) {if (fileiteratorthread.isalive ())
    {Fileiteratorthread.interrupt ();
   Return
   } else {System.out.println ("Enter Quit exit file Scan");
 }}}.start ();
 Fileiteratorthread.start ();

 }
}

In the process of scanning files, the strategy for interrupting detection here is, if the file is not detected interrupt, is the directory to detect the interruption, because the file may be very many, every time the files are detected will reduce the efficiency of the program execution. In addition, in the Fileiteratorthread thread, only the interruptedexception is captured, no reset interrupt state, and no exception continues to be thrown, because I am well aware of its use environment, The upper layer of the call stack for the Run method has no method that might need to detect the interrupt state.

In this program, the input quit can perform the System.exit (0) operation completely to exit the program, but as mentioned earlier, this is a GUI program core logic simulation, in the GUI, execution System.exit (0) will make the entire program exit.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.