深入解析 Java interrupt

Java 中断(Interrupt)机制详解

Java 的中断机制是一种协作式的线程间通信机制,用于请求另一个线程停止当前正在执行的操作。

Thread thread = Thread.currentThread();
thread.interrupt(); // 设置当前线程的中断状态

检查中断状态

// 检查中断状态
boolean isInterrupted = Thread.currentThread().isInterrupted();// 检查并清除中断状态
boolean wasInterrupted = Thread.interrupted();

中断产生的后果

对阻塞方法的影响

当线程在以下阻塞方法中被中断时,会抛出 InterruptedException

try {Thread.sleep(1000);        // sleepobject.wait();             // waitthread.join();             // joinLockSupport.park();        // park// 以及各种 I/O 操作和同步器
} catch (InterruptedException e) {// 中断异常处理Thread.currentThread().interrupt(); // 恢复中断状态
}

对非阻塞代码的影响

对于非阻塞代码,中断不会自动产生异常,需要手动检查:

while (!Thread.currentThread().isInterrupted()) {// 执行任务System.out.println("Working...");// 模拟工作try {Thread.sleep(100);} catch (InterruptedException e) {// 睡眠时被中断Thread.currentThread().interrupt(); // 重新设置中断状态break;}
}
System.out.println("线程被中断,优雅退出");

正确的中断处理模式

1. 传播中断状态

public void task() {try {while (true) {// 执行工作if (Thread.currentThread().isInterrupted()) {throw new InterruptedException();}// 或者检查中断的阻塞操作Thread.sleep(100);}} catch (InterruptedException e) {// 恢复中断状态并退出Thread.currentThread().interrupt();}
}

2. 不可中断任务的处理

public void nonInterruptibleTask() {while (true) {if (Thread.currentThread().isInterrupted()) {// 执行清理操作System.out.println("收到中断请求,执行清理后退出");break;}// 执行不可中断的工作}
}

正确使用中断机制可以实现线程的安全、协作式停止,避免使用已废弃的 stop()方法。

sleep为什么抛出异常

调用本地方法:

    private static native void sleepNanos0(long nanos) throws InterruptedException;

jvm.cpp中注册

JVM_ENTRY(void, JVM_SleepNanos(JNIEnv* env, jclass threadClass, jlong nanos))if (nanos < 0) {THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "nanosecond timeout value out of range");}if (thread->is_interrupted(true) && !HAS_PENDING_EXCEPTION) {THROW_MSG(vmSymbols::java_lang_InterruptedException(), "sleep interrupted");}// Save current thread state and restore it at the end of this block.// And set new thread state to SLEEPING.JavaThreadSleepState jtss(thread);HOTSPOT_THREAD_SLEEP_BEGIN(nanos / NANOSECS_PER_MILLISEC);if (nanos == 0) {os::naked_yield();} else {ThreadState old_state = thread->osthread()->get_state();thread->osthread()->set_state(SLEEPING);if (!thread->sleep_nanos(nanos)) { // interrupted// An asynchronous exception could have been thrown on// us while we were sleeping. We do not overwrite those.if (!HAS_PENDING_EXCEPTION) {HOTSPOT_THREAD_SLEEP_END(1);// TODO-FIXME: THROW_MSG returns which means we will not call set_state()// to properly restore the thread state.  That's likely wrong.THROW_MSG(vmSymbols::java_lang_InterruptedException(), "sleep interrupted");}}thread->osthread()->set_state(old_state);}HOTSPOT_THREAD_SLEEP_END(0);
JVM_END

JVM_SleepNanos这个函数是sleep抛出异常的地方。以下是该函数的核心逻辑:

  1. 首先检查nanos参数是否小于0,如果是则抛出IllegalArgumentException异常(实际上Java层面已经检查了,所以c++层面不会报异常):

  2. if (nanos < 0) {THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "nanosecond timeout value out of range");
    }
    
  3. 检查线程是否已被中断,如果是则抛出InterruptedException异常:

    if (thread->is_interrupted(true) && !HAS_PENDING_EXCEPTION) {THROW_MSG(vmSymbols::java_lang_InterruptedException(), "sleep interrupted");
    }
    
  4. 在实际睡眠过程中,如果线程被中断,也会抛出InterruptedException异常:

    if (!thread->sleep_nanos(nanos)) { // interrupted// An asynchronous exception could have been thrown on// us while we were sleeping. We do not overwrite those.if (!HAS_PENDING_EXCEPTION) {// TODO-FIXME: THROW_MSG returns which means we will not call set_state()// to properly restore the thread state.  That's likely wrong.THROW_MSG(vmSymbols::java_lang_InterruptedException(), "sleep interrupted");}
    }
    

Object.wait异常

同样调用本地方法

    private final native void wait0(long timeoutMillis) throws InterruptedException;

cpp实现在ObjectMonitor.cpp,这个函数很长,简化如下:

// ObjectMonitor的等待方法:处理线程等待、中断和超时逻辑
void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) {JavaThread* current = THREAD;assert(InitDone, "未初始化");CHECK_OWNER();  // 检查所有者,非所有者抛出异常EventJavaMonitorWait wait_event;EventVirtualThreadPinned vthread_pinned_event;// 检查中断状态:若可中断且已中断,直接抛出异常if (interruptible && current->is_interrupted(true) && !HAS_PENDING_EXCEPTION) {JavaThreadInObjectWaitState jtiows(current, millis != 0, interruptible);// 发送JVMTI监控等待事件if (JvmtiExport::should_post_monitor_wait()) {JvmtiExport::post_monitor_wait(current, object(), millis);}if (JvmtiExport::should_post_monitor_waited()) {JvmtiExport::post_monitor_waited(current, this, false);}if (wait_event.should_commit()) {post_monitor_wait_event(&wait_event, this, 0, millis, false);}THROW(vmSymbols::java_lang_InterruptedException());return;}// 虚拟线程处理:尝试挂起虚拟线程freeze_result result;ContinuationEntry* ce = current->last_continuation();bool is_virtual = ce != nullptr && ce->is_virtual_thread();if (is_virtual) {if (interruptible && JvmtiExport::should_post_monitor_wait()) {JvmtiExport::post_monitor_wait(current, object(), millis);}current->set_current_waiting_monitor(this);result = Continuation::try_preempt(current, ce->cont_oop(current));if (result == freeze_ok) {vthread_wait(current, millis);current->set_current_waiting_monitor(nullptr);return;}}// 进入等待状态JavaThreadInObjectWaitState jtiows(current, millis != 0, interruptible);if (!is_virtual) {if (interruptible && JvmtiExport::should_post_monitor_wait()) {JvmtiExport::post_monitor_wait(current, object(), millis);}current->set_current_waiting_monitor(this);}// 创建等待节点并加入等待队列ObjectWaiter node(current);node.TState = ObjectWaiter::TS_WAIT;current->_ParkEvent->reset();OrderAccess::fence();Thread::SpinAcquire(&_wait_set_lock);add_waiter(&node);Thread::SpinRelease(&_wait_set_lock);// 退出监控器并准备挂起intx save = _recursions;_waiters++;_recursions = 0;exit(current);guarantee(!has_owner(current), "invariant");// 挂起线程:检查中断或超时int ret = OS_OK;int WasNotified = 0;bool interrupted = interruptible && current->is_interrupted(false);{OSThread* osthread = current->osthread();OSThreadWaitState osts(osthread, true);assert(current->thread_state() == _thread_in_vm, "invariant");{ClearSuccOnSuspend csos(this);ThreadBlockInVMPreprocess<ClearSuccOnSuspend> tbivs(current, csos, true);if (interrupted || HAS_PENDING_EXCEPTION) {// 空处理:已有中断或异常} else if (!node._notified) {if (millis <= 0) {current->_ParkEvent->park();} else {ret = current->_ParkEvent->park(millis);}}}// 从等待队列移除节点(如果需要)if (node.TState == ObjectWaiter::TS_WAIT) {Thread::SpinAcquire(&_wait_set_lock);if (node.TState == ObjectWaiter::TS_WAIT) {dequeue_specific_waiter(&node);assert(!node._notified, "invariant");node.TState = ObjectWaiter::TS_RUN;}Thread::SpinRelease(&_wait_set_lock);}guarantee(node.TState != ObjectWaiter::TS_WAIT, "invariant");OrderAccess::loadload();if (has_successor(current)) clear_successor();WasNotified = node._notified;// 发送JVMTI监控等待完成事件if (JvmtiExport::should_post_monitor_waited()) {JvmtiExport::post_monitor_waited(current, this, ret == OS_TIMEOUT);if (node._notified && has_successor(current)) {current->_ParkEvent->unpark();}}if (wait_event.should_commit()) {post_monitor_wait_event(&wait_event, this, node._notifier_tid, millis, ret == OS_TIMEOUT);}OrderAccess::fence();// 重新获取监控器锁assert(!has_owner(current), "invariant");ObjectWaiter::TStates v = node.TState;if (v == ObjectWaiter::TS_RUN) {NoPreemptMark npm(current);enter(current);} else {guarantee(v == ObjectWaiter::TS_ENTER, "invariant");reenter_internal(current, &node);node.wait_reenter_end(this);}guarantee(node.TState == ObjectWaiter::TS_RUN, "invariant");assert(has_owner(current), "invariant");assert(!has_successor(current), "invariant");}// 清理状态:重置等待监控器引用current->set_current_waiting_monitor(nullptr);// 恢复递归计数guarantee(_recursions == 0, "invariant");int relock_count = JvmtiDeferredUpdates::get_and_reset_relock_count_after_wait(current);_recursions = save + relock_count;current->inc_held_monitor_count(relock_count);_waiters--;// 验证后置条件assert(has_owner(current), "invariant");assert(!has_successor(current), "invariant");assert_mark_word_consistency();// 虚拟线程事件记录if (ce != nullptr && ce->is_virtual_thread()) {current->post_vthread_pinned_event(&vthread_pinned_event, "Object.wait", result);}// 检查通知结果:未通知可能是超时或中断if (!WasNotified) {if (interruptible && current->is_interrupted(true) && !HAS_PENDING_EXCEPTION) {THROW(vmSymbols::java_lang_InterruptedException());}}
}

ObjectMonitor::wait 函数是 Java 对象监视器(Object Monitor)中实现 Object.wait() 方法的核心函数。它允许线程在对象上等待,直到其他线程调用该对象的 notify() 或 notifyAll() 方法。

1. 初始化和检查

  • 获取当前线程信息并验证初始化状态

  • 使用 CHECK_OWNER() 检查当前线程是否为监视器的所有者,如果不是则抛出 IllegalMonitorStateException

2. 事件初始化

  • 初始化 EventJavaMonitorWait 和 EventVirtualThreadPinned 事件,用于监控和追踪目的

3. 中断检查

  • 如果线程可中断(interruptible 为 true)且已被中断,则在进入等待前抛出 InterruptedException

4. 虚拟线程处理

  • 如果是虚拟线程(virtual thread),则调用 vthread_wait 方法进行特殊处理,包括:

    • 创建 ObjectWaiter 节点

    • 将节点添加到等待队列

    • 处理虚拟线程的挂起和状态转换

5. 常规等待逻辑

对于非虚拟线程或虚拟线程的后续步骤:

  • 创建 JavaThreadInObjectWaitState 对象来管理线程等待状态

  • 如果启用了 JVMTI,则发布 monitor wait 事件

  • 保存当前的递归计数并重置为 0

  • 退出监视器(调用 exit 方法)

  • 增加等待者计数

6. 等待阶段

  • 调用操作系统相关的 park 函数使线程进入等待状态

  • 等待可能因超时、中断或 notify 调用而结束

7. 唤醒后处理

  • 检查唤醒原因(通知、超时或中断)

  • 如果是中断且线程可中断,则抛出 InterruptedException

  • 重新获取监视器锁

  • 恢复递归计数

  • 发布 monitor waited 事件

8. 清理工作

  • 减少等待者计数
  • 清理 successor(如果存在)
  • 删除 ObjectWaiter 节点

这个函数实现了 Java 中对象等待机制的核心逻辑,处理了线程状态管理、同步控制、事件追踪和异常处理等多个方面,确保线程安全地等待和被唤醒。

Thread.join

A线程调用ThreadB.join,实际上就只是调用对方的wait。当线程B结束会唤醒所有的等待者。

/​**​等待该线程终止,最多等待 {@code millis} 毫秒。如果超时时间设为 {@code 0} 则表示无限期等待(直到线程终止)。•如果该线程尚未被 {@link #start() 启动},则此方法会立即返回,无需等待。••@implNote 实现说明:•对于平台线程,该实现采用循环调用 {@code this.wait} 方法,并在 {@code this.isAlive} 条件满足时持续等待。•当线程终止时,会调用 {@code this.notifyAll} 方法唤醒等待的线程。•建议应用程序不要在 {@code Thread} 实例上使用 {@code wait}、{@code notify} 或 {@code notifyAll} 方法,•以避免与线程同步机制发生冲突或造成意外行为。•@throws InterruptedException•如果任何线程中断了当前线程。当抛出此异常时,当前线程的<i>中断状态</i>将被清除。*/public final void join(long millis) throws InterruptedException {if (millis < 0)throw new IllegalArgumentException("timeout value is negative");if (this instanceof VirtualThread vthread) {if (isAlive()) {long nanos = MILLISECONDS.toNanos(millis);vthread.joinNanos(nanos);}return;}synchronized (this) {if (millis > 0) {if (isAlive()) {final long startTime = System.nanoTime();long delay = millis;do {wait(delay);} while (isAlive() && (delay = millis -NANOSECONDS.toMillis(System.nanoTime() - startTime)) > 0);}} else {while (isAlive()) {wait(0);}}}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/97249.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/97249.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SOME/IP-SD事件组订阅

<摘要> 本文将结合AUTOSAR R22-11版本的《PRS_SOMEIPServiceDiscoveryProtocol》规范&#xff0c;解析SOME/IP-SD协议中的事件组订阅机制。针对“事件组订阅”&#xff0c;将从背景概念、设计意图、实际案例及图示等角度展开分析&#xff0c;通过通俗易懂的阐述和图文表格…

龙虎榜——20250829

上证指数今天收小阳线继续站上5天均线&#xff0c;量能稍有回落但仍在200天均量线上&#xff0c;目前均线多头排列依然强势&#xff0c;小级别暂未出现反转信号&#xff0c;但需要注意高低切换的风险。深证指数今天量能略有回落收阳线&#xff0c;创了阶段新高&#xff0c;走势…

vue在函数内部调用onMounted

在 Vue 3 中&#xff0c;函数内部定义的 onMounted 回调&#xff0c;若该函数从未被调用&#xff0c;则 onMounted 不会执行。这一结论的核心逻辑与 Vue 组合式 API&#xff08;Composition API&#xff09;的“调用时机”和“生命周期钩子注册规则”直接相关&#xff0c;具体可…

可解释人工智能XAI

可解释人工智能&#xff08;XAI&#xff09;方法&#xff08;例如常见的XGBoost-SHAP方法&#xff09;可以捕捉到非线性的关系&#xff0c;但这种方法忽略了地理单元之间的空间效应&#xff1b;而传统的空间模型&#xff08;例如常见的GWR&#xff09;虽然考虑了空间效应&#…

Pycharm打包PaddleOCR过程及问题解决方法

python实现提取图片中的文字&#xff0c;使用PaddleOCR识别最精准&#xff0c;因为只需要识别小尺寸图片&#xff0c;速度在一秒钟左右&#xff0c;对于要应用的项目可以接受。缺点是项目打包有将近600M&#xff0c;压缩后也有将近200M。Tesseract虽然速度快&#xff0c;占用空…

Nginx的主要配置文件nginx.conf详细解读——及其不间断重启nginx服务等操作

一、Nginx的配置文件nginx.conf解析 1.1、查看现有已安装的Nginx版本及其编译配置参数等信息 查看现在已有使用的Nginx版本及其编译配置参数等信息序号安装编译Nginx的方式查看现在已有的Nginx版本及其编译配置参数信息方法1使用【yum install nginx -y】命令安装的Nginx #查看…

可改善能源利用水平、削减碳排放总量,并为可再生能源规模化发展提供有力支撑的智慧能源开源了

一、平台简介 AI 视频监控平台是一款功能强大且操作便捷的实时算法视频监控系统。其核心愿景在于打破各大芯片厂商间的技术壁垒&#xff0c;省去繁琐重复的适配流程&#xff0c;实现芯片、算法与应用的全流程协同组合 —— 这一创新可帮助企业级应用降低约 95% 的开发成本。同…

“上门做饭”平台的核心技术栈与运营壁垒是什么?

上门做饭会彻底颠覆外卖行业&#xff0c;成为下一个万亿级风口吗&#xff1f;答案可能出乎你的意料——不会。但这背后&#xff0c;藏着一个更值得关注的真相。前段时间&#xff0c;杭州上门做饭姑娘的新闻刷屏全网&#xff1a;一天接5-6单&#xff0c;每单最低88元。很多人第一…

企业内网与互联网网络安全改造升级深度解析

在信息化时代&#xff0c;企业内网和互联网的安全性直接影响着业务的稳定性和数据的保密性。然而&#xff0c;随着网络威胁的不断升级&#xff0c;传统的网络安全防护手段已难以满足现代企业的需求。为了应对复杂多变的安全挑战&#xff0c;构建“边界清晰、可管可控、多层防御…

参数模板优化配置指南:从基础到进阶的完整解决方案

在数字化运营时代&#xff0c;参数模板优化配置已成为提升系统性能的关键环节。本文将深入解析参数配置的核心逻辑&#xff0c;从基础概念到高级调优技巧&#xff0c;帮助技术人员构建高效稳定的运行环境。我们将重点探讨参数模板的标准化管理方法&#xff0c;以及如何通过精细…

Ubuntu 22.04 中安装 ROS2 Humble

1.4.1前置配置 语言环境支持 UTF-8: sudo apt update && sudo apt install locales sudo locale-gen en_US en_US.UTF-8 sudo update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 export LANG=en_US.UTF-8 启用 Universe 仓库: sudo apt install software-properti…

Python学习-day1

Python学习网站 廖雪峰的官方网站 Python教程 菜鸟教程 Phtyon3教程 W3school Python教程 简明教程 Python教程 牛客网 Python3教程 Python学习网 Python123 Python官网 Python官方教程中文版 Python在线工具 菜鸟工具 Python3在线运行 W3chool在线编译 Python3在线…

为什么外贸企业管理需要外贸CRM系统

CRM&#xff08;Customer Relationship Management&#xff09;系统&#xff0c;即客户关系管理软件&#xff0c;是指利用软件、硬件和网络技术&#xff0c;为企业建立一个客户信息收集、管理、分析和利用的信息系统。为什么外贸企业需要外贸CRM管理系统&#xff1f;传统的客户…

Qt基础_xiaozuo

1.Qt基础Qt三大机制&#xff1a;对象树&#xff0c;信号和槽&#xff0c;事件 特殊类的名词&#xff1a;窗口&#xff0c;组件&#xff0c;控件 2.标准IO #include <QDebug>int main(int argc, char *argv[]) {qDebug() << "字符串&#xff1a;" <&l…

解密PCI Express:现代计算机的“高速公路“是如何设计的?

解密PCI Express&#xff1a;现代计算机的"高速公路"是如何设计的&#xff1f; 当你点击鼠标打开一个大型游戏时&#xff0c;数据是如何从固态硬盘飞速传输到显卡的&#xff1f;这背后离不开一个关键技术的支持——PCI Express。 在现代计算机系统中&#xff0c;各种…

软件安装教程(二):Pycharm安装与配置(Windows)

文章目录前言一、准备工作&#xff08;安装前要求&#xff09;二、下载与安装 PyCharm步骤 1&#xff1a;访问 PyCharm 官网步骤 2&#xff1a;运行安装程序步骤 3&#xff1a;完成安装并启动三、首次启动与配置四、创建项目与配置虚拟环境创建新项目配置虚拟环境五、安装必要的…

Java全栈开发实战:从基础到微服务的深度探索

Java全栈开发实战&#xff1a;从基础到微服务的深度探索 一、面试开场 面试官&#xff08;专业且亲切&#xff09;&#xff1a; 你好&#xff0c;很高兴见到你。我是这次面试的负责人&#xff0c;接下来我们会围绕你的技术背景和项目经验进行一些深入的交流。我们希望了解你在实…

Redis搭建哨兵模式一主两从三哨兵

Redis搭建哨兵模式一主两从三哨兵 目录 Redis搭建哨兵模式一主两从三哨兵 一、Redis哨兵模式 1. 哨兵模式原理&#xff1a; 2. 哨兵的作用&#xff1a; 3.哨兵的结构 4.故障转移机制 故障转移过程如下&#xff1a; 主节点的选举条件&#xff1a; 二、节点规划 三、实…

用 C++ 创建单向链表 forward list

文章目录前言1. 源码 forward_list.hpp2. 使用示例前言 用 C 创建了一个单向链表&#xff0c;用于练习使用现代 C 的特性&#xff0c;包括 3 点&#xff1a; 对于容器&#xff0c;使用 std::initializer_list 作为参数创建构造函数。 C Core Guidelines 中&#xff0c;推荐使…

[肥用云计算] Serverless 多环境配置

前言 在 Serverless 应用开发中&#xff0c;多环境配置是一个绕不开的话题。从开发、测试到生产&#xff0c;每个环境都有其特定的配置需求。阿里云 Serverless Devs 虽然提供了官方的 env 命令来管理多环境&#xff0c;但在实际使用中&#xff0c;我发现官方方案存在一些局限…