End the thread gracefully with join, daemon, interrupt

Time:2020-11-24

Meet join

Simple understanding: created thread T1, ift1.join()To the main thread, then need to wait until T1 thread execution is completed, the main thread can continue to execute

public class ThreadJoin {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            IntStream.range(1, 1000)
                    .forEach(i -> System.out.println(Thread.currentThread().getName() + "->" + i));
        });
        Thread t2 = new Thread(() -> {
            IntStream.range(1, 1000)
                    .forEach(i -> System.out.println(Thread.currentThread().getName() + "->" + i));
        });
        //You must start before you can join
        t1.start();
        t2.start();
        //Here, T1 and T2 are both join to the main thread
        //So T1 and T2 are executed at the same time,
        t1.join();
        t2.join();

        //When T1 and T2 are completed, the following code can be executed
        Optional.of("All of tasks finish done.").ifPresent(System.out::println);
        IntStream.range(1, 1000)
                .forEach(i -> System.out.println(Thread.currentThread().getName() + "->" + i));
    }
}

In the above code, T1 and T2 execute the output alternately. When the execution is completed, it is the main thread output

Of course, you can set the wait timeout

t1.start(); 
//The main thread waits for the T1 thread to execute for 100 milliseconds. After 20 nanoseconds, if T1 has not finished executing yet, // the main thread and T1 execute simultaneously 
t1.join(100,10);

Join can be used to implement the never exit of the main thread

Thread.currentThread().join();

Meet demoan

Simple understanding: the thread created by the parent thread is set tot.setDaemon(true);If the parent thread exits, the background thread T will also exit

public class DaemonThread {

    public static void main(String[] args) throws InterruptedException {

        Thread t = new Thread() {

            @Override
            public void run() {
                try {
                    System.out.println(Thread.currentThread().getName() + " running");
                    Thread.sleep(100000);
                    System.out.println(Thread.currentThread().getName() + " done.");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        t.setDaemon(true);
        t.start();

        //If the parent thread exits after five seconds, the created t guard thread will exit together
        Thread.sleep(5_000);
        System.out.println(Thread.currentThread().getName());
    }
}

Output:
Thread-0 running
main

The parent thread will wait five seconds to finish, and the T thread will end with the main thread

Understand the interrupt() method

Simple understanding: marking a thread with a break flag is not the end of the thread, when the thread issleep(),wait(),join()Will throw outInterruptedExceptionAfter the exception is thrown, the interrupt flag of the thread is restored

public class InterruptTest {
    public static void main(String[] args) {
        Thread t1 = new Thread(()->{
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                System.out.println ("received flag > > > > thread interrupted");
                System.out.println (T1 thread break flag after exception throw > > > "+ Thread.interrupted ());
                e.printStackTrace();
            }
        });

        t1.start();
        //Ensure that the T1 thread is already executing
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //Output flag before break
        System.out.println (flag before T1 interruption > > > "+ T1. Isinterrupted());
        //Interrupt thread
        t1.interrupt();
    }
}

Output:
Flag before T1 break > > > > false
java.lang.InterruptedException: sleep interrupted
Received flag > > > > thread interrupted

at java.lang.Thread.sleep(Native Method)

T1 thread interrupt flag after exception throw > > > false

Note: once an exception is thrown, the interrupt flag will be restored

For t.join(), the parent thread should be interrupted
//Create a thread
        Thread t = new Thread() {
            @Override
            public void run() {
                while (true) {

                }
            }
        };
        //Start thread
        t.start();

        //Save the parent thread
        Thread main = Thread.currentThread();
        //Open the second thread and interrupt the thread on the join method
        Thread t3 = new Thread() {
            @Override
            public void run() {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //Interrupt main thread
                main.interrupt();
                System.out.println("interrupt");
            }
        };

        t3.start();
        try {
            //Note that t.join is actually the main method
            t.join();
        } catch (InterruptedException e) {
            System.out.println ("received interrupt signal > > >");
            e.printStackTrace();
        }

        System.out.println ("main thread continues execution");
    }

Output:
java.lang.InterruptedException
interrupt
Interrupt received > > >
The main thread continues execution

Cause: the parent thread from t.join() is the main thread. You need to interrupt the main thread to catch the interrupt exception

Use these three methods to end the thread reasonably

Scenario: if a task database queries and processes data and cannot be completed within the specified time, the thread needs to be terminated

Create an execution thread executethread in the main thread (can be understood as the main thread), and create a background thread runnerthread in the execution thread to execute the real task
runnerThread.join () to the parent thread. After a certain period of time, the processing is not completed and the execution is completed executeThread.interrupt (). Interrupt the execution thread and catch an exception. The execution thread can execute down without waiting for the runnerthread() to complete

public class ThreadService {

    //Execution thread
    private Thread executeThread;

    //Judge whether it is finished within the specified time
    private volatile boolean finished = false;

    public void execute(Runnable task) {
        executeThread = new Thread() {
            @Override
            public void run() {
                Thread runner = new Thread(task);
                runner.setDaemon(true);

                runner.start();
                try {
                    runner.join();
                    //Normal execution completed
                    finished = true;
                } catch (InterruptedException e) {
                    //If an exception description is caught, the executethread is interrupted
                    //The process continues down and there is no need to wait for the runner to finish
                    //e.printStackTrace();
                }
            }
        };
        //Execution thread启动
        executeThread.start();
    }

    public void shutdown(long mills) {
        long currentTime = System.currentTimeMillis();
        while (!finished) {
            if ((System.currentTimeMillis() - currentTime) >= mills) {
                System.out.println ("task timeout, need to end him!");
                executeThread.interrupt();
                break;
            }
        }

        finished = false;
    }
}

Test case:

public static void main(String[] args) {

        ThreadService2 service = new ThreadService2();
        long start = System.currentTimeMillis();
        service.execute(() -> {
            try {
                //This is a simulated processing task
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        //Waiting for 10m, the task is normally finished
        //service.shutdown(10000);

        //Wait four seconds, the task is forced to end
        service.shutdown(4000);
        long end = System.currentTimeMillis();
        System.out.println(end - start);
    }