Java线程与中断

93 阅读3分钟

在看代码的时候,经常会遇到调用某个线程的interrupt(), 捕获InterruptException等方法,经常不能知其所以然,这里记录一下关于Java线程与中断的相关知识以便于今后查阅

Java线程状态

Java 线程有以下几种状态:

  • 新建状态 (New):线程被创建但尚未启动。
  • 就绪状态 (Runnable):线程已启动并准备好运行,但可能由于 CPU 资源不足而未被调度执行。
  • 运行状态 (Running):线程正在执行。
  • 阻塞状态 (Blocked):线程在等待获取一个锁(例如,调用 synchronized 方法或块时),此时它无法继续执行。
  • 等待状态 (Waiting):线程在等待另一个线程的特定条件(例如,调用 Object.wait()、Thread.join() 或 LockSupport.park())。
  • 超时等待状态 (Timed Waiting):线程在等待某个条件,但有时间限制(例如,调用 Thread.sleep(millis)、Object.wait(millis)、Thread.join(millis))。
  • 终止状态 (Terminated):线程已完成执行。

中断状态

每个线程都有一个中断状态标志,表示该线程是否被请求中断。可以通过以下两个方法检查中断状态:

  • Thread.interrupted() :检查当前线程的中断状态并清除该状态
  • isInterrupted() :检查线程的中断状态,但不会清除该状态

请求中断

当一个线程调用另一个线程的 interrupt() 方法时,目标线程的中断状态会被设置为 true。这表示该线程被请求中断。

阻塞状态下的中断

当线程处于阻塞状态时,如果调用了 interrupt() 方法,线程会抛出 InterruptedException,并且中断状态会被清除(设置为 false)。

会抛出InterruptedException的方法如下:

1. Thread.sleep(long millis)

  • 描述:使当前线程休眠指定的毫秒数。

2. Object.wait()

  • 描述:使当前线程等待,直到其他线程调用 notify() 或 notifyAll() 方法。

3. Object.wait(long timeout)

  • 描述:使当前线程等待,直到其他线程调用 notify() 或 notifyAll() 方法,或者等待指定的时间。

4. Thread.join()

  • 描述:使当前线程等待指定的线程完成执行。

5. Thread.join(long millis)

  • 描述:使当前线程等待指定的线程完成执行,或者等待指定的时间。

6. BlockingQueue.take()

  • 描述:从队列中获取并移除一个元素,如果队列为空,则等待直到有元素可用。

7. BlockingQueue.poll(long timeout, TimeUnit unit)

  • 描述:从队列中获取并移除一个元素,如果队列为空,则等待直到有元素可用或超时。

8. CountDownLatch.await()

  • 描述:使当前线程等待,直到计数器的值为零。

9. CyclicBarrier.await()

  • 描述:使当前线程等待,直到所有参与者都到达屏障。

10. Semaphore.acquire()

  • 描述:获取一个许可,如果没有可用的许可,则等待。

其他状态下的中断

如果线程在运行状态或就绪状态下被中断,线程的中断状态会被设置为 true,但不会抛出异常。线程可以通过检查中断状态来决定是否响应中断请求。

interrupt()方法

职责:它不仅设置中断状态,还在阻塞状态下触发中断异常

  • 如果线程在阻塞状态,会抛出 InterruptedException,并且在这个过程中线程的中断状态会被清除
  • 如果不在阻塞状态,设置中断状态为 true。

InterruptionException

  • 中断异常是一种通知机制,表示线程需要停止当前的阻塞操作
  • 当线程调用可能抛出 InterruptedException 的方法时,必须在 try-catch 块中捕获该异常
  try {
      Thread.sleep(1000); // 当前线程可能抛出 InterruptedException
  } catch (InterruptedException e) {
      // 处理线程被中断的情况
      Thread.currentThread().interrupt(); // 重新设置中断状态
  }

什么时候需要重新设置中断状态

  • 调用 Thread.currentThread().interrupt() 来重新设置中断状态
  • 如果线程的后续逻辑(例如,决定是否停止某个操作)需要检查到该线程曾经被请求中断,则需要在捕获异常后重新设置中断状态。