Java中断的通俗解释

中断请求:

你(线程)正在进行一个任务(比如正在下载文件)。 另一个人(主线程或其他线程)通过按下一个按钮(调用Thread.interrupt())来请求你停止当前任务。

响应中断:

当你接到这个打断请求时,你需要决定如何回应。你可以选择: 立刻停下来:比如你可以抛出一个异常(InterruptedException),立即停止下载,进行清理工作,然后退出任务。 优雅地处理:你可以检查中断状态(调用isInterrupted()或Thread.interrupted()),然后在合适的时候停止任务。比如,如果你正在做一个长时间的计算,你可以在每次计算步骤中检查中断状态,并决定是否继续。

处理中断:

处理完中断请求后,你可能会继续执行其他任务或终止当前任务。这个处理过程可以是同步的(立即响应并停止)或异步的(在下一步检查中处理)。

关键点

①中断不是强制停止: 中断请求只是一种信号,线程需要自己决定如何响应。线程本身不会被“强制停止”,而是通过响应中断来决定是否继续执行。

②中断与状态: 中断机制可以影响线程的状态,例如线程可能会从WAITING、TIMED_WAITING或BLOCKED状态中返回到RUNNABLE状态,但最终的处理逻辑由线程的代码决定。

Java中的中断标志

类比:电话中的“挂断”信号: 假设你正在打电话给某人,电话的另一端传来“挂断”的信号。这时你可能会觉得对方的电话已经结束了,但实际上你希望确认这通电话确实被结束了。为了确保你确实挂断了电话,你会按下手机上的“挂断”按钮,再确认一下电话状态是否正确地被标记为已结束。

在Java中,线程的中断标志就像是电话的“挂断”信号。当线程捕获到InterruptedException异常时,这个信号(中断标志)会被清除,就像电话在接收到挂断信号后自动结束了一样。如果你不重新设置中断标志,就好比你没有确认电话已经挂断,这样其他需要知道电话状态的操作可能会误以为电话仍在进行中。

重新设置中断标志的作用

确保中断信息有效:

当你处理了一个中断请求(比如电话被挂断)后,重新设置中断标志就像是确认电话真的被挂断了一样。这样,其他可能需要知道这个信息的部分(其他线程或操作)可以得到准确的状态信息。

让其他部分知道中断:

重新设置中断标志可以让程序的其他部分知道线程实际上是被中断的。这确保了你在处理完中断后,任何后续的代码都能正确地响应这个中断。

下面代码,如果不恢复中断标志,将永远无法打印Main thread finished.。

  1. public class InterruptPropagationExample {
  2. public static void main(String[] args) throws InterruptedException {
  3. Thread worker = new Thread(() -> {
  4. try {
  5. while (!Thread.currentThread().isInterrupted()) {
  6. // 模拟工作
  7. Thread.sleep(1000); // 可能被中断
  8. }
  9. } catch (InterruptedException e) {
  10. // 捕获异常并恢复中断状态
  11. Thread.currentThread().interrupt(); // 恢复中断状态
  12. System.out.println("Worker thread interrupted.");
  13. }
  14. });
  15. worker.start();
  16. Thread.sleep(2000); // 让线程运行 2 秒
  17. worker.interrupt(); // 发送中断请求
  18. worker.join(); // 等待线程结束
  19. System.out.println("Main thread finished.");
  20. }
  21. }

中断机制运用

打破阻塞状态

线程在执行阻塞操作(如 Thread.sleep 或等待锁)时,中断是一种打破阻塞状态的有效方式。

  1. public class BlockingTask extends Thread {
  2. @Override
  3. public void run() {
  4. try {
  5. Thread.sleep(10000); // 阻塞 10 秒
  6. } catch (InterruptedException e) {
  7. // 被中断时,捕获异常并处理
  8. System.out.println("Thread was interrupted during sleep.");
  9. }
  10. }
  11. public static void main(String[] args) throws InterruptedException {
  12. BlockingTask task = new BlockingTask();
  13. task.start();
  14. Thread.sleep(2000); // 让任务阻塞 2 秒
  15. task.interrupt(); // 中断阻塞
  16. }
  17. }

线程间通信

中断还可以用于线程间通信,例如通知某个线程应当执行某些检查或操作。

  1. public class CommunicationTask extends Thread {
  2. @Override
  3. public void run() {
  4. while (true) {
  5. if (Thread.interrupted()) {
  6. // 执行检查或操作
  7. System.out.println("Thread was interrupted, performing check.");
  8. }
  9. // 其他工作
  10. }
  11. }
  12. public static void main(String[] args) throws InterruptedException {
  13. CommunicationTask task = new CommunicationTask();
  14. task.start();
  15. Thread.sleep(2000); // 让任务运行 2 秒
  16. task.interrupt(); // 通知执行检查
  17. }
  18. }