sleep and how to terminate threads correctly

Why should Thread.sleep() throw an interrupt exception or put it in try-catch?

Because: while sleeping, you must also be aware of external conditions, that is, you must be able to respond to interrupts. For example, when calling interrupt(), you actually want to end the thread as soon as possible. Therefore, continuing sleep is meaningless and should end as soon as possible.

 public static void main(String[] args) {<!-- -->
        Thread thread = new Thread(){<!-- -->
            @Override
            public void run() {<!-- -->
                try {<!-- -->
                    sleep(10000);
                } catch (InterruptedException e) {<!-- -->
                    System.out.println("sleep state was interrupted!");
                    e.printStackTrace();
                }
            }
        };
        thread. start();
        // Mark the interrupt thread after sleeping for two seconds
        try {<!-- -->
            sleep(2000);
            thread. interrupt();
        } catch (InterruptedException e) {<!-- -->
            e.printStackTrace();
        }
    }

How to terminate a thread correctly?

The most direct way to terminate is to call stop(), which can directly end the execution of the thread, but it has been deprecated.

This method was originally designed to stop the thread and throw a thread death exception, but in fact it is unsafe because it directly terminates the thread to release the lock, which is difficult to correctly throw a thread death exception for processing.

Therefore, a better way is to set a judgment condition, and then judge the condition during the execution of the thread to decide whether to stop the thread, so that the thread can be processed and exited in an orderly manner. If a thread waits for a long time, it will directly interrupt the thread and throw an exception.

As mentioned above, we can set a variable for control. Of course, we can declare a bool type for judgment, but a better way is to use interrupt().

 Thread thread = new Thread(){<!-- -->
            @Override
            public void run() {<!-- -->
                while (!isInterrupted()){<!-- -->
                    System.out.println("Thread is running");
                }
            }
        };
        thread. start();
        // Mark the interrupt thread after sleeping for two seconds
        try {<!-- -->
            sleep(2000);
            thread. interrupt();
        } catch (InterruptedException e) {<!-- -->
            e.printStackTrace();
        }

What is worth noting in the above code is that in the thread.interrupt() method, the thread’s private volatile boolean interrupted is only set to true, so it still needs to be passed in the original thread. isInterrupted() method to check

interrupt() and isInterrupted() source code:

 public void interrupt() {<!-- -->
        if (this != Thread.currentThread()) {<!-- -->
            checkAccess();

            // thread may be blocked in an I/O operation
            synchronized (blockerLock) {<!-- -->
                Interruptible b = blocker;
                if (b != null) {<!-- -->
                    interrupted = true;
                    interrupt0(); // inform VM of interrupt
                    b.interrupt(this);
                    return;
                }
            }
        }
        interrupted = true;
        // inform VM of interrupt
        interrupt0();
    }

public boolean isInterrupted() {<!-- -->
        return interrupted;
    }

In addition to the above methods, you can also determine whether to terminate by judging the volatile boolean variable in while:

 static class Runner implements Runnable{<!-- -->
        private volatile boolean on = true;
        private long i = 0;
        @Override
        public void run() {<!-- -->
            while (on & amp; & amp; !Thread.currentThread().isInterrupted()){<!-- -->
                i + + ;
            }
            System.out.println("Count i = " + i);
        }
        
        public void cancel(){<!-- -->
            on = false;
        }
    }

The interrupt operation or flag bit method allows the thread to have the opportunity to clean up resources when it terminates, instead of arbitrarily stopping the thread, which is safer and more elegant.

Interrupt clear

Generally, the code will be written like this: (Purpose: After sleeping for 100 milliseconds, determine whether the thread is interrupted, and if it is not interrupted, continue to execute the business

 try {<!-- -->
Thread.sleep(100);
} catch (InterruptedException e) {<!-- -->
//The interrupt flag has been cleared
}
// Thread.currentThread().isInterrupted(): Whether it was interrupted (whether there is an interrupt flag)
if(!Thread.currentThread().isInterrupted()) {<!-- -->
//If not interrupted, process the business
doSomething();
}

But even if the thread is interrupted during sleep, our code below will still execute. why? This is because sleep will erase the interrupt flag. When an exception is thrown, the interrupt status of the thread will be cleared:

What should we do if we want to determine whether the thread has been interrupted after sleeping for 100 milliseconds, and if not, continue to execute the business? It’s very simple. We can manually interrupt this thread again, so that the business code will not be executed:

 try {<!-- -->
Thread.sleep(100);
} catch (InterruptedException e) {<!-- -->
//The interrupt flag has been cleared
// Manually interrupt this thread and set the interrupt signal on this thread.
Thread.currentThread().interrupt();
}
// Thread.currentThread().isInterrupted(): Whether it was interrupted (whether there is an interrupt flag)
if(!Thread.currentThread().isInterrupted()) {<!-- -->
//If not interrupted, process the business
doSomething();
}

interrupted() and isinterrupted()

interrupted() is a static method that checks the interruption status of the current thread and clears the interruption status: If the thread is interrupted, that is, the interruption status is true, the interrupted() method will return true and will Reset interrupt status to false. If the thread has not been interrupted, that is, the interruption status is false, the interrupted() method will return false.

And isInterrupted() is an instance method

If you want to throw an exception, etc., it is recommended to use the interrupted method

while( Thread. interrupted() ){<!-- -->
throws new InterruptedException;
}

Code test verification comparison

Practical combat

List shutdownNow(): Send interrupt signals to all executing task threads. Tasks waiting in the queue will be returned

 ExecutorService executorService = Executors.newFixedThreadPool(1);
        executorService. execute(()->{<!-- -->
            //The task keeps running
            while (true) {<!-- -->
                System.out.println("1");
            }
        });
        Thread. sleep(3000);
        executorService. shutdownNow();
System.out.println("shutdown");



ExecutorService executorService = Executors.newFixedThreadPool(1);
        executorService. execute(()->{<!-- -->
            //The task keeps running
            while (!Thread.currentThread().isInterrupted()) {<!-- -->
                System.out.println("1");
            }
        });
        Thread. sleep(3000);
        executorService. shutdownNow();
        System.out.println("shutdown");

Explanation of shutdownNow method: There are no guarantees beyond best-effort attempts to stop processing actively executing tasks. This implementation interrupts tasks via Thread.interrupt; any task that fails to respond to interrupts may never terminate

In this method, the interrupt() method of each thread t is finally called, so the first while true will always output 1 and cannot be stopped. The second method stops after 3s and finally prints shutdown.