Five years of experience, I still don't know how to terminate threads gracefully

foreword

Stopping a thread means stopping the operation being done before the task finishes processing the task, that is, giving up the current operation. You can use Thread.stop()the method to stop a thread, but it is best not to use it. While it is true that a running thread can be stopped, this method is unsafe and deprecated.

1. Unstoppable threads

interrupt()The effect of using a method is not like for+breaka statement, which immediately stops the loop. The calling interruptmethod is to put a stop sign in the current thread, and it does not really stop the thread.

public class MyThread extends Thread {  
    public void run(){  
        super.run();  
        for(int i=0; i<500000; i++){  
            System.out.println("i="+(i+1));  
        }  
    }  
}  
  
public class Run {  
    public static void main(String args[]){  
        Thread thread = new MyThread();  
        thread.start();  
        try {  
            Thread.sleep(2000);  
            thread.interrupt();  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
    }  
}  

Output result:

...  
i=499994  
i=499995  
i=499996  
i=499997  
i=499998  
i=499999  
i=500000  

2. Determine whether the thread is stopped

Thread.javaThe class provides two methods:

  • this.interrupted(): Test whether the current thread has been interrupted;

  • this.isInterrupted(): Test whether the thread has been interrupted;

So what is the difference between these two methods?

Let's take a look at this.interrupted()the explanation of the method first: test whether the current thread has been interrupted, the current thread refers to this.interrupted()the thread running the method.

public class MyThread extends Thread {  
    public void run(){  
        super.run();  
        for(int i=0; i<500000; i++){  
            i++;  
//            System.out.println("i="+(i+1));  
        }  
    }  
}  
  
public class Run {  
    public static void main(String args[]){  
        Thread thread = new MyThread();  
        thread.start();  
        try {  
            Thread.sleep(2000);  
            thread.interrupt();  
  
            System.out.println("stop 1??" + thread.interrupted());  
            System.out.println("stop 2??" + thread.interrupted());  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
    }  
}  

operation result:

stop 1??false  
stop 2??false  

Although the following code is called on the thread object in the class Run.java: thread.interrupt(), it is used later

System.out.println("stop 1??" + thread.interrupted());  
System.out.println("stop 2??" + thread.interrupted());    

To judge whether the thread represented by the thread object is stopped, but from the results printed on the console, the thread has not stopped, which also proves the interrupted()explanation of the method, and tests whether the current thread has been interrupted. The current thread is main, it has never been interrupted, so the printed result is two false. How to make the main thread interrupt effect?

public class Run2 {  
    public static void main(String args[]){  
        Thread.currentThread().interrupt();  
        System.out.println("stop 1??" + Thread.interrupted());  
        System.out.println("stop 2??" + Thread.interrupted());  
  
        System.out.println("End");  
    }  
}      

The running effect is:

stop 1??true  
stop 2??false  
End  

method interrupted()does determine whether the current thread is stopped. But why the second boolean value is false? Explanation of the method in the official help document interrupted: Test whether the current thread has been interrupted. The thread's interrupt status is cleared by this method. In other words, if the method is called twice in a row, the second call returns false. Let's take a look at inInterrupted()the method.

public class Run3 {  
    public static void main(String args[]){  
        Thread thread = new MyThread();  
        thread.start();  
        thread.interrupt();  
        System.out.println("stop 1??" + thread.isInterrupted());  
        System.out.println("stop 2??" + thread.isInterrupted());  
    }  
}  

operation result:

stop 1??true  
stop 2??true  

isInterrupted()And to clear the state, so two trues are printed.

3. Threads that can be stopped - exception method

With the knowledge points learned earlier, you can use the for statement in the thread to judge whether the thread is in the stopped state. If it is in the stopped state, the following code will not run anymore:

public class MyThread extends Thread {  
    public void run(){  
        super.run();  
        for(int i=0; i<500000; i++){  
            if(this.interrupted()) {  
                System.out.println("线程已经终止, for循环不再执行");  
                break;  
            }  
            System.out.println("i="+(i+1));  
        }  
    }  
}  
  
public class Run {  
    public static void main(String args[]){  
        Thread thread = new MyThread();  
        thread.start();  
        try {  
            Thread.sleep(2000);  
            thread.interrupt();  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
    }  
}  

operation result:

...  
i=202053  
i=202054  
i=202055  
i=202056  

The thread has terminated and the for loop is no longer executed. Although the above example stops the thread, if there are statements under the for statement, it will continue to run. See the example below:

public class MyThread extends Thread {  
    public void run(){  
        super.run();  
        for(int i=0; i<500000; i++){  
            if(this.interrupted()) {  
                System.out.println("线程已经终止, for循环不再执行");  
                break;  
            }  
            System.out.println("i="+(i+1));  
        }  
  
        System.out.println("这是for循环外面的语句,也会被执行");  
    }  
}  

The result of using Run.java is:

...  
i=180136  
i=180137  
i=180138  
i=180139  

The thread has terminated and the for loop is no longer executed. This is a statement outside the for loop, and it will also be executed. How to solve the problem that the statement continues to run? Take a look at the updated code:

public class MyThread extends Thread {  
    public void run(){  
        super.run();  
        try {  
            for(int i=0; i<500000; i++){  
                if(this.interrupted()) {  
                    System.out.println("线程已经终止, for循环不再执行");  
                        throw new InterruptedException();  
                }  
                System.out.println("i="+(i+1));  
            }  
  
            System.out.println("这是for循环外面的语句,也会被执行");  
        } catch (InterruptedException e) {  
            System.out.println("进入MyThread.java类中的catch了。。。");  
            e.printStackTrace();  
        }  
    }  
}  

The result of running with Run.java is as follows:

...  
i=203798  
i=203799  
i=203800  
线程已经终止, for循环不再执行  
进入MyThread.java类中的catch了。。。  
java.lang.InterruptedException  
    at thread.MyThread.run(MyThread.java:13)  

4. Threads that can be stopped---violent stop

Using stop()methods to stop threads is very violent.

public class MyThread extends Thread {  
    private int i = 0;  
    public void run(){  
        super.run();  
        try {  
            while (true){  
                System.out.println("i=" + i);  
                i++;  
                Thread.sleep(200);  
            }  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
    }  
}  
  
public class Run {  
    public static void main(String args[]) throws InterruptedException {  
        Thread thread = new MyThread();  
        thread.start();  
        Thread.sleep(2000);  
        thread.stop();  
    }  
}  

operation result:

i=0  
i=1  
i=2  
i=3  
i=4  
i=5  
i=6  
i=7  
i=8  
i=9  
  
Process finished with exit code 0  

5. Method stop() and java.lang.ThreadDeath exception

stop()An exception is thrown when the method is called java.lang.ThreadDeath, but normally, this exception does not need to be explicitly caught.

public class MyThread extends Thread {  
    private int i = 0;  
    public void run(){  
        super.run();  
        try {  
            this.stop();  
        } catch (ThreadDeath e) {  
            System.out.println("进入异常catch");  
            e.printStackTrace();  
        }  
    }  
}  
  
public class Run {  
    public static void main(String args[]) throws InterruptedException {  
        Thread thread = new MyThread();  
        thread.start();  
    }  
}  

stop()method and invalidated, because if the thread is forced to stop, some cleaning work may not be completed. Another situation is that the locked object is unlocked, resulting in the data not being processed synchronously, and the problem of data inconsistency occurs.

6. Bad consequences of releasing the lock

Using stop()release locks will result in inconsistent data. If such a situation occurs, the data processed by the program may be destroyed, which will eventually lead to an error in the program execution process. Special attention must be paid to:

public class SynchronizedObject {  
    private String name = "a";  
    private String password = "aa";  
  
    public synchronized void printString(String name, String password){  
        try {  
            this.name = name;  
            Thread.sleep(100000);  
            this.password = password;  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
    }  
  
    public String getName() {  
        return name;  
    }  
  
    public void setName(String name) {  
        this.name = name;  
    }  
  
    public String getPassword() {  
        return password;  
    }  
  
    public void setPassword(String password) {  
        this.password = password;  
    }  
}  
  
public class MyThread extends Thread {  
    private SynchronizedObject synchronizedObject;  
    public MyThread(SynchronizedObject synchronizedObject){  
        this.synchronizedObject = synchronizedObject;  
    }  
  
    public void run(){  
        synchronizedObject.printString("b", "bb");  
    }  
}  
  
public class Run {  
    public static void main(String args[]) throws InterruptedException {  
        SynchronizedObject synchronizedObject = new SynchronizedObject();  
        Thread thread = new MyThread(synchronizedObject);  
        thread.start();  
        Thread.sleep(500);  
        thread.stop();  
        System.out.println(synchronizedObject.getName() + "  " + synchronizedObject.getPassword());  
    }  
}  

Output result:

b  aa  

Due to stop()the method and the method marked as "expired/obsolete" in the JDK, it is obviously functionally flawed, so it is not recommended to use the stop() method in the program.

7. Use return to stop the thread

Combining the method interrupt()with return can also achieve the effect of stopping the thread:

public class MyThread extends Thread {  
    public void run(){  
        while (true){  
            if(this.isInterrupted()){  
                System.out.println("线程被停止了!");  
                return;  
            }  
            System.out.println("Time: " + System.currentTimeMillis());  
        }  
    }  
}  
  
public class Run {  
    public static void main(String args[]) throws InterruptedException {  
        Thread thread = new MyThread();  
        thread.start();  
        Thread.sleep(2000);  
        thread.interrupt();  
    }  
}  

Output result:

...  
Time: 1467072288503  
Time: 1467072288503  
Time: 1467072288503  
线程被停止了!  

However, it is still recommended to use the method of "throwing an exception" to stop the thread, because the exception can also be thrown upwards in the catch block, so that the thread stop event can be propagated.

Guess you like

Origin blog.csdn.net/qq_28165595/article/details/129103127