在上述 interrupt-1 代码中如果加入 sleep 方法,那么我们会发现程序报出 InterruptedException 错误,同时,线程 interrupt-1 也不会停止,这里就是因为中断标记被复位了 ,下面我们来介绍一下关于中断标记复位相关的内容
在线程类中提供了** **Thread.interrupted 的静态方法,用来对线程中断标识的复位,在上面的代码中,我们可以做一个小改动,对 interrupt-1 线程创建的代码修改如下:
//创建 interrupt-1 线程 Thread thread = new Thread(() -> { while (true) { //判断当前线程是否中断, if (Thread.currentThread().isInterrupted()) { System.out.println("线程1 接收到中断信息,中断线程...中断标记:" + Thread.currentThread().isInterrupted()); Thread.interrupted(); // //对线程进行复位,由 true 变成 false System.out.println("经过 Thread.interrupted() 复位后,中断标记:" + Thread.currentThread().isInterrupted()); //再次判断是否中断,如果是则退出线程 if (Thread.currentThread().isInterrupted()) { break; } } System.out.println(Thread.currentThread().getName() + "线程正在执行..."); } }, "interrupt-1");上述代码中 我们可以看到,判断当前线程是否处于中断标记为 true , 如果有其他程序通知则为 true 此时进入 if 语句中,对其进行复位操作,之后再次判断。执行代码后我们发现 interrupt-1 线程不会终止,而会一直执行
Thread.interrupted 进行线程中断标记复位是一种主动的操作行为,其实还有一种被动的复位场景,那就是上面说的当程序出现 InterruptedException 异常时,则会将当前线程的中断标记状态复位,在抛出异常前, JVM 会将中断标记 isInterrupted 设置为 false
在程序中,线程中断复位的存在实际就是当前线程对外界中断通知信号的一种响应,但是具体响应的内容有当前线程决定,线程不会立马停止,具体是否停止等都是由当前线程自己来决定,也就是开发者。
3.3 线程终止 interrupt 的原理
首先我们先来看一下在 Thread 中关于 interrupt 的定义:
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) { // <1> 调用 native 方法 interrupt0(); // set interrupt status b.interrupt(this); return; } } } // set interrupt status interrupt0(); }上面代码中我们可以看到,在 interrupt 方法中最终调用了 Native 方法 interrupt0 ,这里相关在线程启动时说过,不再赘述,我们直接找到 hotspot 中 jvm.cpp 文件中 JVM_Interrupt 方法
JVM_Interrupt 方法比较简单,其中我们可以看到直接调用了 Thread.cpp 的 interrupt 方法,我们进入其中查看
我们可以看到这里直接调用了 os::interrupt(thread) 这里是调用了平台的方法,对于不同的平台实现是不同的,我们这里如下所示,选择 Linux 下的实现 os_linux.cpp 中,
在上面代码中我们可以看到,在 1 处拿到 OSThread ,之后判断如果 interrupt 为 false 则在 2 处调用 OSThread 的 set_interrupted 方法进行设置,我们可以进入看一下其实现,发现在 osThread.hpp 中定义了一个成员变量 volatile jint _interrupted; 而 set_interrupted 方法其实就是将 _interrupted 设置为 true ,之后再通过 ParkEvent 的 unpark() 方法来唤醒线程。具体的过程在上面进行的简单的注释介绍,
本文由AnonyStar 发布,可转载但需声明原文出处。
仰慕「优雅编码的艺术」 坚信熟能生巧,努力改变人生
欢迎关注微信公账号 :云栖简码 获取更多优质文章
更多文章关注笔者博客 :云栖简码