How to properly stop a thread

How to stop the thread correctly

New thread

There are many ways to create a new thread
  • Implement the Runnable interface and override the run() method
  • Inherit the Thread class and override the run() method
  • Implement the callable interface and rewrite the call method
  • use thread pool
  • use timer
Code example – Runnable interface

The Runnable interface overrides the run method

public class NewRunnable implements Runnable{<!-- -->
    @Override
    public void run() {<!-- -->
        System.out.println("I am NewRunnable Thread");
    }

    public static void main(String[] args) {<!-- -->
        NewRunnable newRunnable = new NewRunnable();
        Thread thread = new Thread(newRunnable);
        thread. start();
    }
}

// result
/*
    I am New Runnable Thread
*/

In the above code, the newly created NewRunnable class implements the Runnable interface and rewrites the run method to create a new thread. It may not reflect multi-threading in this way, and a loop can be added.

public class NewThread {<!-- -->

    public static void main(String[] args) {<!-- -->

        Thread thread = new Thread(new Runnable() {<!-- -->
            @Override
            public void run() {<!-- -->
                for (int i = 0; i < 5; i ++ ) {<!-- -->
                    try {<!-- -->
                        Thread. sleep(200);
                        System.out.println("i am " + i);
                    } catch (InterruptedException e) {<!-- -->
                        e.printStackTrace();
                    }

                }
            }
        });
        thread. start();
        try {<!-- -->
            Thread. sleep(500);
            System.out.println("i am mainThread");
        } catch (InterruptedException e) {<!-- -->
            e.printStackTrace();
        }
    }

operation result

i am 0
i am 1
i am mainThread
i am 2
i am 3
i am 4

Use an anonymous inner class to rewrite the run method of the Runnable interface, and then loop five times, sleep for 200 milliseconds each time, and sleep for 500 milliseconds in the main thread, so when the child thread loops twice, the main thread starts printing in the middle of the third printing .

Code example-Thread class

Inherit the Thread class

public class NewThread extends Thread {<!-- -->

    @Override
    public void run() {<!-- -->
        System.out.println("I am NewThread!");
    }

    public static void main(String[] args) {<!-- -->
        NewThread newThread = new NewThread();
        newThread. start();
    }
}
/*
   I am NewThread!
*/
New thread summary

Whether it is implementing the Runnable interface or inheriting the Thread class, it is found that the thread is finally started by the start() method of the Thread class, not by the run() method. Take a look at the source code of the run method and the start method

run() method
public class Thread implements Runnable {<!-- -->
    
    public Thread(Runnable target) {<!-- -->
        init(null, target, "Thread-" + nextThreadNum(), 0);
    }
    
    @Override
    public void run() {<!-- -->
        if (target != null) {<!-- -->
            target. run();
        }
    }
}

It is found that Thread also implements the Runnable interface and rewrites the run method. As shown above, we are using the Runnable interface and passing the object as a parameter to the public Thread(Runnable target) in the Thread class; when the constructor, at this time The run() method executes the run() method of the incoming object, and there are only these three lines of code in the run() method, so multi-threading is not implemented.

start() method
public synchronized void start() {<!-- -->
    /**
     * This method is not invoked for the main method thread or "system"
     * group threads created/set up by the VM. Any new functionality added
     * to this method in the future may have to also be added to the VM.
     *
     * A zero status value corresponds to state "NEW".
     */
    if (threadStatus != 0)
        throw new IllegalThreadStateException();

    /* Notify the group that this thread is about to be started
     * so that it can be added to the group's list of threads
     * and the group's unstarted count can be decremented. */
    group. add(this);

    boolean started = false;
    try {<!-- -->
        start0();
        started = true;
    } finally {<!-- -->
        try {<!-- -->
            if (!started) {<!-- -->
                group. threadStartFailed(this);
            }
        } catch (Throwable ignore) {<!-- -->
            /* do nothing. If start0 throw a Throwable then
              it will be passed up the call stack */
        }
    }
}

You can see that the first run() method if (threadStatus != 0) judges the thread status, and then calls the start0 method, and the start0 method private native void start0(); can Seeing that it is a native method, not implemented by java

learned after searching

In Java, the Thread class is a class used to implement multi-threaded programming. When we create a new thread and start it, we actually call the start() method in the Thread class, which executes a local method start0(). The start0() method starts a new system thread and calls the run() method. The run() method is the code executed by the thread. When the run() method is executed, the thread will automatically end.

The start0() method is a native method, which is implemented by the JVM. Native methods refer to methods written in low-level languages such as C/C++, which are usually loaded by the JVM and executed on the local system. The start0() method realizes the creation and startup of threads at the bottom layer, and its specific implementation will depend on different operating systems and JVM implementations. In the JVM, the implementation of the start0() method is provided by the native layer, so we cannot directly view its source code.

So we can know that the real implementation of multithreading in java is the start() method in the Thread class.

Add callable interface
public class NewCallable implements Callable {<!-- -->
    @Override
    public String call() throws Exception {<!-- -->
        String s = "I am newCallable!";
        System.out.println(Thread.currentThread().getName());

        return s;
    }

    public static void main(String[] args) {<!-- -->
        NewCallable newCallable = new NewCallable();

        FutureTask futureTask = new FutureTask<>(newCallable);
        Thread thread = new Thread(futureTask);
        thread. start();
        try {<!-- -->
            Object o = futureTask. get();
            System.out.println(o);
        } catch (InterruptedException e) {<!-- -->
            e.printStackTrace();
        } catch (ExecutionException e) {<!-- -->
            e.printStackTrace();
        }
        System.out.println("i am mainThread");
        System.out.println(Thread.currentThread().getName());


    }
}

/*
    Thread-0
    I am newCallable!
    i am mainThread
    main
*/

It can be seen that implementing the callable interface is also a new thread created through the Thread class. The difference is that the FutureTask class is used to receive the return value

Briefly talk about futureTask, you can see that this class indirectly inherits the Runnable interface, so it can still be understood as the callable interface is to implement the Runnbale interface, and it is realized by rewriting the run method Multi-threading, other methods will not be explained too much.

Stop the thread

How to stop the thread?
  • stop()?
  • destroy()?
  • suspend()?
  • interrupt()?

Looking at the API, we will see that the java.lang.Thread type provides a series of methods such as start(), stop(), resume(), suspend(), destroy() and other methods to manage thread. But apart from start(), several other methods are declared as deprecated (deprecated)

For detailed reasons, see the explanation of the jdk document

https://docs.oracle.com/javase/1.5.0/docs/guide/misc/threadPrimitiveDeprecation.html

The correct way to stop a thread is to use the interrupt() method

Interrupt() method

In Java, the Thread.interrupt() method is used to interrupt the thread, and its function is to set the interrupt flag of the thread to true. The interrupted thread can determine whether it is interrupted by checking its own interrupt flag bit, and then perform appropriate operations.

If the thread is blocked on certain operations (such as waiting for I/O operations, sleep(), etc.), calling the interrupt() method will interrupt the blocking state of the thread, Throw an InterruptedException exception and clear the interrupt flag. If the thread is not blocked, calling the interrupt() method just sets the interrupt flag of the thread to true, and the thread can still continue to run.

Give me an example
public class MyThread extends Thread {<!-- -->
    public void run() {<!-- -->
        try {<!-- -->
            while (!Thread.currentThread().isInterrupted()) {<!-- -->
                System.out.println("MyThread is running...");
                Thread. sleep(1000);
            }
        } catch (InterruptedException e) {<!-- -->
            System.out.println("MyThread is interrupted!");
        }
    }

    public static void main(String[] args) {<!-- -->
        MyThread myThread = new MyThread();
        myThread. start();
        try {<!-- -->
            Thread. sleep(5000);
        } catch (InterruptedException e) {<!-- -->
            e.printStackTrace();
        }
        myThread. interrupt();
    }
}

// result
/*
    MyThread is running...
    MyThread is running...
    MyThread is running...
    MyThread is running...
    MyThread is running...
    MyThread is interrupted!
*/

A new thread is created. In the main thread, we interrupt the new thread after sleeping for 5S. This is the new thread capturing the interrupt and printing MyThread is interrupted!,

Interrupt flag

In the above code, if we replace while (!Thread.currentThread().isInterrupted()) with while (true), we find that the result is the same. Why? This involves the interrupt flag bit, as mentioned above **If the thread is blocked on some operations (such as waiting for I/O operations, sleep(), etc.), call interrupt The () method will interrupt the blocking state of the thread, throw an InterruptedException exception, and clear the interrupt flag bit. **When the thread is interrupted for 5s in the above code, the thread is in the sleep state. At this time, the program throws InterruptedException and clears the interrupt flag. The thread has stopped when the exception is thrown.

public class MyThread extends Thread {<!-- -->
    public void run() {<!-- -->
            int i = 0;
            while (!Thread.currentThread().isInterrupted()){<!-- -->
                System.out.println("Printing:" + + + i);
            }

    }

    public static void main(String[] args) {<!-- -->
        MyThread myThread = new MyThread();
        myThread. start();
        int sum = 0;
        for (int i = 0; i < 1000000; i ++ ) {<!-- -->
            sum + = i;
        }
        myThread. interrupt();
    }
}


// result
/*
Printing: 0
Printing: 1
Printing: 2
Printing: 3
?…
Printing: 104
*/

You can see that we execute the code by judging the interrupt signal of the program. When the program is interrupted, we jump out of the while loop and the new thread ends.

Cautions for use in loops

If we put try catch in the loop and find that the program does not stop after responding to the interrupt, it is because sleep () clears the interrupt flag bit, so the try catch statement cannot be placed in the loop, but should be placed outside the loop.

public class MyThread extends Thread {<!-- -->
    public void run() {<!-- -->
        while (!Thread.currentThread().isInterrupted()) {<!-- -->
            try {<!-- -->
                System.out.println("MyThread is running...");
                Thread. sleep(500);
            } catch (InterruptedException e) {<!-- -->
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {<!-- -->
        MyThread myThread = new MyThread();
        myThread. start();
        try {<!-- -->
            Thread. sleep(2000);
        } catch (InterruptedException e) {<!-- -->
            e.printStackTrace();
        }
        myThread. interrupt();
    }
}

result

/*
MyThread is running...
MyThread is running...
MyThread is running...
MyThread is running...
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at threadToStop.MyThread.run(MyThread.java:8)
MyThread is running...
MyThread is running...
    */