寫Java并發代碼的人,今年都在聊StructuredTaskScope。fork-join模型干凈、虛擬線程便宜,看起來所有異步問題都有了標準答案。
直到你遇到一個需要等支付確認的步驟。
![]()
不是等幾毫秒,不是等下游服務回個HTTP 200。是徹底讓出執行,把狀態落盤,等一個可能幾小時后、甚至JVM重啟之后才來的外部事件。這時候你會發現:STS的結構化,是空間上的結構化——所有fork的任務綁定在一個活著的調用棧上。它不負責時間。
這是Exeris Kernel系列第五篇。前面四篇鋪了很長的路:用ScopedValue換掉ThreadLocal,論證某些層不需要運行時多態,把TLS徹底踢出堆外。這一篇講STS在哪里停住,以及必須造什么來補位。
壓力來自具體的場景。我在做Kernel的編排層——帶補償邏輯、能接外部事件的多步驟業務流程。先看了一圈現成的:Camunda、Axon,還有同類企業級saga框架。全否了。它們要單獨跑一個進程,有自己的JVM、內存 footprint、生命周期。Kernel的其他約束——零分配熱路徑、ScopedValue透傳、堆外狀態——也塞不進去。
于是往下沉一層。STS起初看起來是天然選擇。fork工作,join結果,生命周期有保證。Loom讓這很便宜。
然后撞上那個支付確認的步驟。
邊界在這里劃清:一旦執行邊界需要跨越時間而非作用域,你就徹底離開了STS的地盤。這不是批評——STS沒有被替換。Kernel里現在還有幾處用它,而且用法跟入門教程不太一樣。
第一處是直觀的。單個Flow步驟內部,一個動作要調兩個獨立服務、合并結果再返回FlowOutcome.CONTINUE。執行綁在這個步驟的虛擬線程上,STS管fan-out,Flow管步驟邊界。標準結構化并發。
第二處在L3,Events子系統里。InMemoryEventBus.publishAndAwait開個scope,每個注冊handler fork一個虛擬線程,join,等全完再返回。CommunityEventLoop.dispatchBatch也是這個形狀,節奏不同:每批drained的事件,每個fork一個VT。
特別聲明:以上內容(如有圖片或視頻亦包括在內)為自媒體平臺“網易號”用戶上傳并發布,本平臺僅提供信息存儲服務。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.