現象:jstack 輸出中,BLOCKED 狀態線程的堆疊幀顯示 -locked <addr>,與持鎖線程完全一致,理論上只有持鎖線程才應顯示 -locked,等待線程應顯示 -waiting to lock。
jstack 發送 threaddump 命令 → Attach Listener 執行 VM_PrintThreadsVMThread 在安全點執行:SafepointSynchronize::begin() 持有 Threads_lockObjectMonitor::enter() → 設置 ThreadBlockInVM 狀態ThreadBlockInVM 檢測到安全點同步中(_synchronizing),調用 SafepointSynchronize::block() 卡在 Threads_lockSelf->set_current_pending_monitor(this) 未執行javaVFrame::print_lock_info_on() 判斷 mark->monitor() != current_pending_monitor 為 false,誤判為持鎖// ObjectMonitor::enter 關鍵片段
JavaThreadBlockedOnMonitorEnterState jtbmes(jt, this); // 設置線程狀態 BLOCKED
// ... 省略 DTrace/JVMTI 埋點 ...
ThreadBlockInVM tbivm(jt); // 此處可能卡住
Self->set_current_pending_monitor(this); // 關鍵設置被跳過
// print_lock_info_on 判斷邏輯
if (mark->has_monitor() && mark->monitor() == thread->current_pending_monitor())
lock_state = "waiting to lock";
else
lock_state = "locked"; // 因 current_pending_monitor 為 NULL,誤入此分支
將 Self->set_current_pending_monitor(this) 前移至 ThreadBlockInVM 之前:
Self->set_current_pending_monitor(this); // 先設置
ThreadBlockInVM tbivm(jt); // 再進入安全點阻塞
現象 → 工具原理 → 源碼調用鏈 → 競態條件定位 → 最小化修復 → 迴歸驗證。養成「帶著問題查源碼」習慣,方能觸類旁通。