背景
之前某需求在触发流控时需要中断ExcutorService中的子线程,发现无论Shutdown、ShutdownNow方法都无法直接停止子线程,今天看到线程的interrupt()方法才了解如何停止。
stop() 和 interrupt()
stop方法
stop() 方法会真的杀死线程,不给线程喘息的机会,如果线程持有 ReentrantLock 锁,被 stop() 的线程并不会自动调用 ReentrantLock 的 unlock() 去释放锁,那其他线程就再也没机会获得 ReentrantLock 锁,类似的方法还有 suspend() 和 resume() 方法。故已不建议使用。
interrupt方法
interrupt() 方法仅仅是通知线程,线程有机会执行一些后续操作,同时也可以无视这个通知。
被 interrupt 的线程,是怎么收到通知的呢?一种是异常,另一种是主动检测。
异常
-
当线程 A 处于 WAITING、TIMED_WAITING 状态时,如果其他线程调用线程 A 的 interrupt() 方法,会使线程 A 返回到 RUNNABLE 状态,同时线程 A 的代码会触发 InterruptedException 异常
-
当线程 A 处于 RUNNABLE 状态时,并且阻塞在IO上时。如阻塞在java.nio.channels.InterruptibleChannel 上时,如果其他线程调用线程 A 的 interrupt() 方法,线程 A 会触发 java.nio.channels.ClosedByInterruptException 这个异常;而阻塞在 java.nio.channels.Selector 上时,如果其他线程调用线程 A 的 interrupt() 方法,线程 A 的 java.nio.channels.Selector 会立即返回。
tips: 这里的状态为Java线程状态:NEW(初始化状态)RUNNABLE(可运行 / 运行状态)BLOCKED(阻塞状态)WAITING(无时限等待)TIMED_WAITING(有时限等待)TERMINATED(终止状态)
主动检查
线程处于 RUNNABLE 状态,并且没有阻塞在某个 I/O 操作上,得依赖线程 A 主动检测中断状态。
如果其他线程调用线程 A 的 interrupt() 方法,那么线程 A 可以通过 isInterrupted() 方法,检测是不是自己被中断。
public class Main {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> {
for (int i = 0; i < 10000000; i++) {
System.out.println(i);
if (Thread.currentThread().isInterrupted()) {
System.out.println("find Interrupted");
break;
}
}
});
ExecutorService executors = Executors.newFixedThreadPool(1);
// 线程池执行
System.out.println("excute");
executors.execute(t);
// 等待0.5秒
Thread.sleep(500);
// 线程池中断
executors.shutdownNow();
t.join();
}
}
如果子线程不检测isInterrupted()并主动停止,那么会继续运行下次。
中断标记与清楚
interrupt()会给对象线程打上中断标记,而捕获InterruptedException异常会清除标记。
Thread.currentThread().isInterrupted()不会清除标记。
shutdown()和shutdownNow()
shutdown方法只会取消等待中的任务,而shutdownNow方法还会给执行中的任务打上中断标记。
标签:状态,ShutdownNow,Thread,中断,线程,Shutdown,interrupt,方法 From: https://www.cnblogs.com/kiper/p/17231281.html