Byteman 使用指南(八)

FunTester發表於2025-02-12

預設Helper類提供了以下標準內建呼叫套件,供在規則表示式中使用。這些主要用於條件和動作表示式中,但它們也可以在事件繫結中被呼叫。它們提供的功能旨在使執行復雜測試變得容易,特別是協調多執行緒應用程式中執行緒的動作。內建操作分為三類:執行緒協調操作、規則狀態管理操作和跟蹤與除錯操作。

執行緒協調操作

1. 等待者(Waiters)

規則引擎提供了 Waiters,用於在規則執行期間掛起執行緒,然後讓其他執行緒喚醒它們。喚醒可以簡單地允許掛起的執行緒繼續執行它所暫停的規則,或者強制等待的執行緒從觸發方法中以異常退出。Helper類定義的 API 如下:

public void waitFor(Object identifier)
public void waitFor(Object identifier, long millisecsWait)
public boolean waiting(Object identifier)
public boolean signalWake(Object identifier)
public boolean signalWake(Object identifier, boolean mustMeet)
public boolean signalThrow(Object identifier)
public boolean signalThrow(Object identifier, boolean mustMeet)

與 CountDowns 一樣,Waiters 由任意物件標識。需要注意的是,等待操作並不是透過在識別符號上呼叫 Object.wait 來執行的,這樣做可能會干擾觸發方法或其呼叫者執行的鎖定和同步操作。識別符號僅用於規則引擎,以關聯等待和訊號操作。Helper類使用其自己的私有 Waiter 物件來管理同步活動。

  • waitFor

    該方法旨在在規則動作中使用。它暫停當前執行緒,直到對相同識別符號呼叫 signalWakesignalThrow。在前一種情況下,執行緒將繼續處理任何後續動作,然後從觸發呼叫中返回。在後一種情況下,執行緒將從觸發方法呼叫框架中丟擲執行時異常。沒有等待引數的版本永遠不會超時,而帶有等待引數的版本將在指定的毫秒數過後超時。

  • waiting

    該方法旨在在規則條件中使用。如果有任何執行緒在相關 Waiter 上等待訊號,它將返回 true;如果沒有執行緒在等待,它將返回 false

  • signalWake

    該方法旨在在規則條件或動作中使用。如果有任何執行緒在 identifier 標識的 Waiter 上等待,它會喚醒它們並返回 true;如果沒有,它將返回 false

注意:這種行為確保了多個執行緒嘗試從規則條件發出訊號以喚醒等待執行緒之間的競爭只能有一個贏家。

可選引數 mustMeet

在無法保證等待執行緒會在訊號執行緒到達其觸發點之前到達其觸發點的情況下,mustMeet 引數非常有用。如果此引數設定為 true,訊號執行緒將不會傳遞其訊號,直到另一個執行緒在等待。如果必要時,訊號執行緒將掛起,直到一個等待執行緒到達。提供值 false 相當於省略可選引數。

  • signalThrow
    該方法與 signalWake 類似,但它不僅僅喚醒任何等待的執行緒,還導致它們從其觸發方法呼叫框架中丟擲執行時異常 ExecuteException
    signalThrow 也接受一個可選引數 mustMeet,其行為與 signalWake 相同。

2. 集合點(Rendezvous)

Waiters 在存在不對稱關係的情況下非常有用:一個或多個執行緒需要等待由另一個執行緒發出的事件。集合點提供了一種在沒有這種不對稱性的情況下進行同步的方法。集合點還提供了一種引入不對稱性的方式,因為它按到達順序對執行緒進行排序。從集合點內建返回的值可以被檢查,以識別,例如,第一個(或最後一個)到達的執行緒,這個執行緒可以是觸發其動作的執行緒。

API 方法

public boolean createRendezvous(Object identifier, int expected)
public boolean createRendezvous(Object identifier, int expected, boolean rejoinable)
public boolean rendezvous(Object identifier)
public boolean rendezvous(Object identifier, long timeout)
public boolean isRendezvous(Object identifier, int expected)
public int getRendezvous(Object identifier, int expected)
public int deleteRendezvous(Object identifier, int expected)
  • createRendezvous

    建立一個透過 identifier 標識的集合點。count 引數標識必須在任何執行緒繼續執行之前在集合點相遇的執行緒數量。可選引數 rejoinable 預設為 false,在這種情況下,任何嘗試在第一批計數執行緒到達後相遇的嘗試都會失敗。如果設定為 true,那麼一旦計數執行緒到達,集合點將被重置,允許另一輪相遇發生。如果集合點被成功建立,createRendezvous 返回 true;如果已經存在一個透過識別符號標識的集合點,則返回 false

    注意:提供計數為 1 是合法的(儘管病態)。

  • rendezvous

    該方法被呼叫以在透過 identifier 標識的集合點與其他執行緒相遇。如果到達集合點的執行緒數量(包括呼叫執行緒)小於預期計數,那麼呼叫執行緒將被掛起。如果執行緒數量等於預期計數,那麼所有掛起的執行緒將被喚醒。如果是可重新加入的集合點,則已到達計數將重置為 0;如果不是可重新加入的集合點,那麼它將被刪除,任何後續呼叫 rendezvous 使用原始識別符號的呼叫將返回 -1

    rendezvous 也可以傳遞一個超時引數,標識呼叫者應該等待所有執行緒到達的毫秒數。如果超時時間超過了預期數量的執行緒到達集合點的時間,並且沒有達到預期數量的執行緒,那麼將從呼叫中丟擲(執行時)異常。零或負的超時值意味著不要超時。

  • isRendezvous

    該方法返回 true,如果有一個透過識別符號標識的集合點處於活動狀態,並且具有預期的計數。如果沒有透過識別符號標識的處於活動狀態的集合點,或者它存在但有不同的預期計數,則返回 false

  • getRendezvous

    該方法返回在透過 identifier 標識的集合點等待的執行緒數量。如果沒有執行緒當前在等待,它將返回 0。如果沒有透過 identifier 標識的集合點,或者它存在但有不同的預期計數,則返回 -1

  • deleteRendezvous

    該方法刪除一個集合點,打破了 identifier 與集合點之間的關聯,並強制任何在 rendezvous 呼叫下等待的執行緒立即返回,結果為 -1。如果找到併成功刪除了具有正確預期計數的集合點,它將返回 true;如果沒有這樣的集合點,或者它被另一個併發呼叫 deleteRendezvous() 或因為一個併發呼叫 rendezvous() 完成了集合點而被刪除,它將返回 false

3. 加入者(Joiners)

Joiners 在需要確保一個執行緒在繼續之前等待一個或多個相關執行緒退出的情況下非常有用。這並不總是應用程式正確執行的要求,但可能需要驗證測試場景。例如,套接字監聽器執行緒可能會建立連線管理器執行緒來處理傳入的連線請求。監聽器可能使用連線物件通知連線管理器執行緒強制退出。它不一定需要保留對連線執行緒的控制代碼,並顯式呼叫 Thread.join() 以確保執行緒退出時被通知。然而,測試可能想要檢查執行緒池以確保所有活動都已完成。這意味著測試需要能夠累積一個管理執行緒列表,然後隨後從管理器執行緒或測試執行緒加入它們。

API 方法

public boolean createJoin(Object identifier, int expected)
public boolean isJoin(Object identifier, int expected)
public boolean joinEnlist(Object identifier)
public boolean joinWait(Object identifier, int expected)
public boolean joinWait(Object identifier, int expected, long timeout)
  • createJoin

    建立一個隨後可以引用的 Joiner,透過 identifier 標識。expected 引數標識將要加入的執行緒數量。如果建立了 Joiner,則返回 true;如果已經透過識別符號識別了 Joiner,則返回 false

  • isJoin

    測試 identifier 是否標識了一個具有給定預期計數的 Joiner。如果透過 identifier 識別的 Joiner 具有給定的預期計數,則返回 true,否則返回 false

  • joinEnlist

    將呼叫執行緒新增到與 Joiner 相關聯的執行緒列表中,並返回 true,允許執行緒向退出繼續。如果 identifier 沒有識別 Joiner,則返回 false。如果呼叫執行緒已經在 Joiner 的執行緒列表中,或者新增到列表中的執行緒數量達到了建立 Joiner 時提供的 expected 計數,它也會返回 false

  • joinWait

    掛起呼叫執行緒,直到與 Joiner 相關聯的執行緒列表中的執行緒數量達到預期計數。然後它加入每個執行緒,並返回 true。如果 identifier 沒有識別 Joiner,或者識別的 Joiner 有錯誤的 expected 計數,則返回 false

    joinWait 也可以傳遞一個超時引數,標識呼叫者應該等待執行緒計數達到預期計數和隨後的 join 操作完成的毫秒數。如果超時時間超過了預期數量的執行緒到達的等待時間,並且沒有達到預期數量的執行緒,那麼將從呼叫中丟擲(執行時)異常。零或負的超時值意味著不要超時。

4. 中止執行

規則引擎提供了兩個用於規則動作的內建方法,允許中止觸發方法的執行。Helper類定義的 API 如下:

public void killThread()
public void killJVM()
public void killJVM(int exitCode)
  • killThread

    導致在觸發方法呼叫框架中丟擲型別為 ExecuteException 的執行時異常。這將有效地殺死執行緒,除非在呼叫堆疊的某個位置安裝了捕獲所有異常的異常處理程式。

  • killJVM

    導致呼叫 java.lang.Runtime.getRuntime().halt()。這有效地殺死了 JVM,沒有任何機會讓任何註冊的退出處理程式執行,模擬了 JVM 崩潰。如果未提供 exitCode,它預設為 -1

FunTester 原創精華

【連載】從 Java 開始效能測試

  • 混沌工程、故障測試、Web 前端
  • 服務端功能測試
  • 效能測試專題
  • Java、Groovy、Go
  • 白盒、工具、爬蟲、UI 自動化
  • 理論、感悟、影片
如果覺得我的文章對您有用,請隨意打賞。您的支援將鼓勵我繼續創作!
打賞支援
暫無回覆。