[Reserved] Java programming logic (69) - interrupted thread

This section focuses on the question of how to cancel or close a thread in Java?

Cancel / closing scenes

We know that after the start method to start a thread by thread, the thread begins execution method run, after the run method runs the thread exits, then why do you need it the end of a thread? There are a variety of situations, such as:

  • Many threads running mode is an infinite loop, such as the producer / consumer model, the consumer body is an infinite loop, it kept to accept the task from the queue, perform tasks in stopping the program, we need a " elegant "way to close the thread.
  • In some graphical user interface program, a thread is a user-initiated, complete some tasks, such as downloading a file from a remote server, the download process, the user may wish to cancel the task.
  • In some scenarios, such as the results of a query from a third party server, we hope to get results within a limited time, if not, we will want to cancel the task.
  • Sometimes, we will start doing the same thing multiple threads, such as similar to rob the train, we could make more friends to help buy a train ticket from multiple sources, as long as there is a channel available, we will notify cancel other sources.

Cancel mechanisms / off

Thread Java class defines the following methods:

public final void stop()

This method looks can stop the thread, but this method is marked for obsolete, simply, that we should not use it, you can ignore it.

In Java, the main mechanism to stop a thread is interrupted, the interrupt is not forced to terminate a thread, it is a cooperative mechanism, it is to pass a thread cancel signal, but to decide how and when to exit a thread, in this section we Java is mainly to understand the mechanism of interruption.

Thread class defines the following method on interrupt:

public boolean isInterrupted()
public void interrupt()
public static boolean interrupted() 

These three methods similar name, relatively easy to confuse us an explanation. isInterrupted () and interrupt () is an instance method, they need to call the thread object, interrupted () is a static method, the actual calls Thread.currentThread () operation of the current thread.

Each thread has a flag indicating whether the thread is interrupted.

  • isInterrupted: that is, returns the corresponding thread interrupt flag is is true.
  • interrupted: Returns the current thread's interrupt flag is is true, but it also has an important side effect, interrupt flag is cleared, that is, two consecutive calls interrupted (), the first result returned is true, the first secondary general is false (unless at the same time there was a break).
  • interrupt: an interrupt corresponding thread, interrupt specific What do you mean? Let's further illustrated.

Thread interrupt response

interrupt () affect the state of the thread and the thread performing IO operations related to, let's consider the main thread state:

  • RUNNABLE: threads are running or have run conditions just waiting for the operating system scheduler
  • WAITING / TIMED_WAITING: thread waiting for some condition or timeout
  • BLOCKED: threads wait for a lock, trying to get into sync blocks
  • NEW / TERMINATED: thread has not started or has ended

RUNNABLE

If the thread is running, without an IO operation, interrupt () just sets the thread's interrupt flag, no other effect. Thread should check the appropriate interrupt flag bit position during operation, for example, if the subject code is one cycle, can be checked at the beginning of the cycle, as follows:

Copy the code
public class InterruptRunnableDemo extends Thread {
    @Override
    public void run() {
        while (!Thread.currentThread().isInterrupted()) {
            // ... 单次循环代码
        }
        System.out.println("done ");
    }

    public static void main(String[] args) throws InterruptedException {
        Thread thread = new InterruptRunnableDemo();
        thread.start();
        Thread.sleep(1000);
        thread.interrupt();
    }
}
Copy the code

WAITING/TIMED_WAITING

Thread executing the following method will enter WAITING state:

public final void join() throws InterruptedException
public final void wait() throws InterruptedException

Use the following method will enter TIMED_WAITING state:

public final native void wait(long timeout) throws InterruptedException;
public static native void sleep(long millis) throws InterruptedException;
public final synchronized void join(long millis) throws InterruptedException

In these states, calls interrupt thread object () will cause the thread throws InterruptedException, should be noted that, after an exception is thrown, the interrupt flag will be cleared, instead of being set up. For example, execute the following code:

Copy the code
Thread t = new Thread (){
    @Override
    public void run() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            System.out.println(isInterrupted());
        }
    }        
};
t.start();
try {
    Thread.sleep(100);
} catch (InterruptedException e) {
}
t.interrupt();
Copy the code

The output of the program is false.

InterruptedException is a subject to exceptions, threads must be processed. We introduced in exception handling, the basic idea of ​​exception handling is that if you know how to deal with it is processed, if you do not know, it should be passed up, under normal circumstances, you should not do is catch the exception and then ignored.

Capture InterruptedException, usually expressed the hope that the end of the thread, the thread is probably handled in two ways:

  1. The exception is passed up, which makes the method has become a method of interrupt, the caller needs to be processed.
  2. In some cases, an exception can not be passed up, such as Thread run method, which statement is fixed and can not throw any abnormal subjects, then, should catch the exception, carried out the appropriate cleanup operations after the cleaning, the general should call Thread interrupt method set the interrupt flag so that other codes have the means to know what it was interrupted.

Sample Code The first way is as follows:

public void interruptibleMethod() throws InterruptedException{
    // ... 包含wait, join 或 sleep 方法
    Thread.sleep(1000);
}

A second embodiment of the sample code is as follows:

Copy the code
public class InterruptWaitingDemo extends Thread {
    @Override
    public void run() {
        while (!Thread.currentThread().isInterrupted()) {
            try {
                // 模拟任务代码
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                // ... 清理操作
                // 重设中断标志位
                Thread.currentThread().interrupt();
            }
        }
        System.out.println(isInterrupted());
    }

    public static void main(String[] args) {
        InterruptWaitingDemo thread = new InterruptWaitingDemo();
        thread.start();
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
        }
        thread.interrupt();
    }
}
Copy the code

BLOCKED

If the thread is waiting for the lock, thread object to call interrupt () just sets the thread's interrupt flag, the thread will still be in BLOCKED state, that is to say, interrupt () does not make a thread waiting for the lock real "break." We look at the code section:

Copy the code
public class InterruptSynchronizedDemo {
    private static Object lock = new Object();

    private static class A extends Thread {
        @Override
        public void run() {
            synchronized (lock) {
                while (!Thread.currentThread().isInterrupted()) {
                }
            }
            System.out.println("exit");
        }
    }

    public static void test() throws InterruptedException {
        synchronized (lock) {
            A a = new A();
            a.start();
            Thread.sleep(1000);

            a.interrupt();
            a.join();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        test();
    }
}
Copy the code

test method to start a thread in the case of a lock holding the lock, and also to try to get a thread lock lock, it will lock into the waiting queue, and then test the calling thread a method of interrupt and wait for the end of a thread in the thread, a thread will end ? Not, interrupt method will only set the thread interrupt flag, but it does not come out from the lock wait queue.

We slightly modify the code to remove the last line a.join test methods, i.e., becomes:

Copy the code
public static void test() throws InterruptedException {
    synchronized (lock) {
        A a = new A();
        a.start();
        Thread.sleep(1000);

        a.interrupt();
    }
}
Copy the code

At this time, the program will quit. why? Because the main thread is no longer waiting for the end of a thread, release the lock lock, the thread will get a lock, then detects that an interrupt occurs, it will quit.

In the process of using the synchronized keyword to obtain the lock does not respond to the interrupt request, it is synchronized limitations. If this program is a problem, you should use explicit locks, the later chapters we will introduce explicit lock Lock interface, which supports a way of responding to the interrupt acquire the lock.

NEW/TERMINATE

If the thread has not been started (NEW), or has ended (TERMINATED), is called interrupt () it has no effect, interrupt flag will not be set. For example, the following code output is false.

Copy the code
public class InterruptNotAliveDemo {
    private static class A extends Thread {
        @Override
        public void run() {
        }
    }

    public static void test() throws InterruptedException {
        A a = new A();
        a.interrupt();
        System.out.println(a.isInterrupted());

        a.start();
        Thread.sleep(100);
        a.interrupt();
        System.out.println(a.isInterrupted());
    }

    public static void main(String[] args) throws InterruptedException {
        test();
    }
}
Copy the code

IO operations

If the thread is waiting for IO operations, especially network IO, then there will be some special treatment, we have not introduced network, here is a brief introduction.

  • If the IO channel is interrupted, that is, to achieve a InterruptibleChannel interface, the thread's interrupt flag will be set at the same time, the thread will receive an exception ClosedByInterruptException.
  • If the calling thread is blocked in Selector, the thread interrupt flag will be set up, at the same time, blocking call returns immediately.

We focus on another case, read the InputStream calls, the operation is not interrupted, if the stream data, read will block (but the thread state is still RUNNABLE), and does not respond to interrupt (), and synchronized similar call interrupt () will set the thread interrupt flag, but not really "break" it, we look at the code segment.

Copy the code
public class InterruptReadDemo {
    private static class A extends Thread {
        @Override
        public void run() {
            while(!Thread.currentThread().isInterrupted()){
                try {
                    System.out.println(System.in.read());
                } catch (IOException e) {
                    e.printStackTrace();
                }    
            }
            System.out.println("exit");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        A t = new A();
        t.start();
        Thread.sleep(100);

        t.interrupt();
    }
}
Copy the code

Call System.in.read () reads from standard input a character, do not enter any characters after the thread t starts, we will see, calling interrupt () will not be interrupted read (), the thread will run.

However, there is a way to interrupt read () call that close call flow method, we will change the code to:

Copy the code
public class InterruptReadDemo {
    private static class A extends Thread {
        @Override
        public void run() {
            while (!Thread.currentThread().isInterrupted()) {
                try {
                    System.out.println(System.in.read());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("exit");
        }

        public void cancel() {
            try {
                System.in.close();
            } catch (IOException e) {
            }
            interrupt();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        A t = new A();
        t.start();
        Thread.sleep(100);

        t.cancel();
    }
}
Copy the code

We define a thread to cancel method, in this method, call the close method streams, while calling the interrupt method, this time, the program will output:

-1
exit

That is, the method calls the close, read method returns, the return value of -1, indicating the end of the stream.

How do I cancel / close the thread correctly

Above, we can see that, interrupt method is not necessarily real "break" thread, it is only a cooperation mechanism, if you do not know what to do in the thread, the thread should not call the interrupt method of rushed, thinking that it will be able to cancel a thread.

Program modules to threads provide services is concerned, it should cancel the package on / off operation, a separate canceled / closed to the caller method, a method similar to cancel InterruptReadDemo demonstrated, the external caller should call these methods instead of calling interrupt.

Some code Java concurrency library provides a separate cancellation on / off method, for example, Future interface provides a method to cancel tasks: 

boolean cancel(boolean mayInterruptIfRunning);

As another example, ExecutorService Close provides the following two methods:

void shutdown();
List<Runnable> shutdownNow();

Future and ExecutorService API documentation for these methods are described in detail, this is what we should learn. About two interfaces, we introduce later chapters.

summary

This section explains how to cancel / close the thread in Java technology is mainly dependent on the interruption, but it is a coordination mechanism, will not be forced to terminate a thread, we introduced threads response to interruptions in the different states and IO operations as implementers thread should provide a clear cancellation on / off method, and use documents clearly describe its behavior, as the caller thread should use its cancellation on / off method, rather than hastily calling interrupt.

From Day 65 to this section, we introduce the basic elements are on the thread, there is a set of concurrent toolkit in Java, located under the package java.util.concurrent, which includes many ease of use and high-performance concurrent development tools, from the beginning of the next section, we'll discuss it, start with the most basic variables and atomic CAS operation.

Guess you like

Origin www.cnblogs.com/ivy-xu/p/12363549.html