Byteman 使用指南(八)
默认Helper
类提供了以下标准内置调用套件,供在规则表达式中使用。这些主要用于条件和动作表达式中,但它们也可以在事件绑定中被调用。它们提供的功能旨在使执行复杂测试变得容易,特别是协调多线程应用程序中线程的动作。内置操作分为三类:线程协调操作、规则状态管理操作和跟踪与调试操作。
线程协调操作
1. 等待者(Waiters)
规则引擎提供了 Waiters
,用于在规则执行期间挂起线程,然后让其他线程唤醒它们。唤醒可以简单地允许挂起的线程继续执行它所暂停的规则,或者强制等待的线程从触发方法中以异常退出。Helper
类定义的 API 如下:
与 CountDowns 一样,Waiters 由任意对象标识。需要注意的是,等待操作并不是通过在标识符上调用 Object.wait
来执行的,这样做可能会干扰触发方法或其调用者执行的锁定和同步操作。标识符仅用于规则引擎,以关联等待和信号操作。Helper
类使用其自己的私有 Waiter 对象来管理同步活动。
waitFor
:该方法旨在在规则动作中使用。它暂停当前线程,直到对相同标识符调用
signalWake
或signalThrow
。在前一种情况下,线程将继续处理任何后续动作,然后从触发调用中返回。在后一种情况下,线程将从触发方法调用框架中抛出运行时异常。没有等待参数的版本永远不会超时,而带有等待参数的版本将在指定的毫秒数过后超时。waiting
:该方法旨在在规则条件中使用。如果有任何线程在相关 Waiter 上等待信号,它将返回
true
;如果没有线程在等待,它将返回false
。signalWake
:该方法旨在在规则条件或动作中使用。如果有任何线程在
identifier
标识的 Waiter 上等待,它会唤醒它们并返回true
;如果没有,它将返回false
。注意:这种行为确保了多个线程尝试从规则条件发出信号以唤醒等待线程之间的竞争只能有一个赢家。
可选参数
mustMeet
:在无法保证等待线程会在信号线程到达其触发点之前到达其触发点的情况下,
mustMeet
参数非常有用。如果此参数设置为true
,信号线程将不会传递其信号,直到另一个线程在等待。如果必要时,信号线程将挂起,直到一个等待线程到达。提供值false
相当于省略可选参数。signalThrow
:该方法与
signalWake
类似,但它不仅仅唤醒任何等待的线程,还导致它们从其触发方法调用框架中抛出运行时异常ExecuteException
。signalThrow
也接受一个可选参数mustMeet
,其行为与signalWake
相同。
2. 集合点(Rendezvous)
Waiters 在存在不对称关系的情况下非常有用:一个或多个线程需要等待由另一个线程发出的事件。集合点提供了一种在没有这种不对称性的情况下进行同步的方法。集合点还提供了一种引入不对称性的方式,因为它按到达顺序对线程进行排序。从集合点内置返回的值可以被检查,以识别,例如,第一个(或最后一个)到达的线程,这个线程可以是触发其动作的线程。
API 方法
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 方法
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 如下:
killThread
:导致在触发方法调用框架中抛出类型为
ExecuteException
的运行时异常。这将有效地杀死线程,除非在调用堆栈的某个位置安装了捕获所有异常的异常处理程序。killJVM
:导致调用
java.lang.Runtime.getRuntime().halt()
。这有效地杀死了 JVM,没有任何机会让任何注册的退出处理程序运行,模拟了 JVM 崩溃。如果未提供exitCode
,它默认为-1
。
版权声明: 本文为 InfoQ 作者【FunTester】的原创文章。
原文链接:【http://xie.infoq.cn/article/9494e1479e0b49789dca21abd】。文章转载请联系作者。
评论