线程中断以后还能被重新拉起吗?

线程被中断后就会先处理中断异常,执行完中断异常后,在继续执行这个代码块中后续的代码。全部代码执行完成后,该任务就已经结束了,不会被再次拉起了。

public static void main(String[] args) throws InterruptedException {  
    ExecutorService executorService = Executors.newCachedThreadPool();  
    Future<?> threadRun = executorService.submit(() -> {  
        try {  
            Thread.sleep(2000);  
            // 一旦触发中断了,这个触发中断语句的后面的代码就不会执行了  
            System.out.println("Thread run");  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
            System.out.println("Thread interrupted:处理中断异常");  
        }  
        System.out.println("处理完成中断异常后继续执行接下来的代码");  
    });  
    Thread.sleep(1000);  
    // 相当于是触发所有的任务中断  
    //executorService.shutdownNow();  
    // 触发线程池中单个任务的中断  
    threadRun.cancel(true);  
    System.out.println("Main run");  
}

如果没有中断异常,也没有中断检测interrupted(),executorService.shutdownNow();是如何结束线程池中的线程的?

shutdownNow() 方法会采取的操作

  1. 尝试中断线程
    • shutdownNow() 会遍历线程池中的所有工作线程,并调用每个线程的 interrupt() 方法。
    • 这会设置线程的中断状态,但不会强制终止线程。线程需要自行检查其中断状态或响应中断异常来终止执行。
  2. 返回未执行的任务
    • shutdownNow() 方法会立即尝试停止所有正在执行的任务,并返回一个 List<Runnable> 列表,其中包含那些尚未开始执行的任务。
  3. 任务的处理
    • 调用者可以检查这个返回的列表,决定如何处理这些未执行的任务。例如,可以选择重新提交这些任务到另一个线程池,或者记录日志以便后续处理。
  4. 线程池的状态
    • 调用 shutdownNow() 方法后,线程池将不再接受新的任务提交。
    • 线程池的状态会立即变为 STOP,这意味着线程池将不再启动任何新的线程来执行任务。

线程不响应中断的情况

  • 如果线程的任务代码没有检查中断状态,也没有执行可能抛出 InterruptedException 的操作,那么调用 shutdownNow() 后,该线程可能不会立即终止。
  • 在这种情况下,线程会继续执行完当前任务,除非任务本身包含某种机制来检测中断或响应外部信号。

实际应用建议

设计可中断的任务

为了确保线程池中的线程能够响应 shutdownNow(),建议设计任务时考虑中断机制。例如,定期检查中断状态,或在可能阻塞的操作中捕获 InterruptedException

样例代码

public class LongTimeTaskExecutorInterrupt {  
  
    public static void main(String[] args) throws InterruptedException {  
        ExecutorService executorService = Executors.newCachedThreadPool();  
        Future<?> threadRun = executorService.submit(() -> {  
            while(true) {  
                // 模拟执行任务  
                for (int i = 0; i < 100; i++) {  
                    System.out.println("task run:" + i);  
                }  
                System.out.println("task run success");  
                try {  
                    Thread.sleep(1);  
                    // 一旦触发中断了,这个触发中断语句的后面的代码就不会执行了  
                    System.out.println("Thread run");  
                } catch (InterruptedException e) {  
                    System.out.println("Thread run 响应中断");  
                    throw new RuntimeException(e);  
                }  
                System.out.println("处理完成中断异常后/正常执行完中断检查的代码后 继续执行接下来的代码");  
            }  
        });  
        Thread.sleep(1000);  
        // 相当于是触发所有的任务中断  
        executorService.shutdownNow();  
        System.out.println("Main run");  
    }  
  
}
  • 使用自定义线程池和策略
    • 如果需要更细粒度的控制,可以考虑使用自定义的 ThreadPoolExecutor,并在其中实现特定的中断和关闭策略。