深入解析 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
英文地址,請注明出處:http://en.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;我發現官方方案存在一些局限…