我有一个应用程序应该(在某些情况下)防止多个线程。为了进行测试,我需要同时从多个线程调用一个方法。
class MyObject {
val myMethodCalled = new AtomicBoolean()
def myMethod() = {
if (myMethodCalled.getAndSet(true))
throw new IllegalStateException("Do not call myMethod twice")
}
}
我想从测试用例中触发上述方法中的异常。
这可能在JVM
吗?如果是的话,该怎么做?
我想知道是否有任何方法(使用某些技巧或我不知道的类)在虚拟机中同时调用方法。我猜这是不可能的。
答案 0 :(得分:1)
你应该通过在它的中间睡眠(Thread.sleep
)或做一些耗时的繁忙工作来减慢方法的处理速度,然后让两个或更多其他线程尽可能快地调用该方法。
您还可以抽象出仅运行一次的功能,以便您可以单独测试它。 E.g。
def onlyOnce[A](f: => A) = {
if (myMethodCalled.getAndSet(true)) throw new Exception("Twice!")
f
}
然后当你需要测试这实际上是否有效时,你传入一个缓慢执行的f
来简化测试。否则,用你曾经的方法
def doSomething = onlyOnce {
}
如果您已正确测试onlyOnce
,则不会出错(假设事情被正确封装,以便f
的主体不会弄乱myMethodCalled
的值。)< / p>
最后,你最好的选择是使用一台至少有三个实际执行线程的机器,并且其中两个执行繁忙等待,其中一个翻转另一个正在读取的volatile var,然后运行该方法。这本身并不可靠,但是如果你在两者之间有很小的忙等待偏移并且多次覆盖相关空间,你至少可以做一个统计论证,你至少几乎一直都没事。
答案 1 :(得分:0)
只需将你的def改为懒惰,你可以保证它只运行一次:
object MyObject {
// static field
val myMethodCalled = new AtomicBoolean()
// static method
lazy val myMethod = {
if (myMethodCalled.getAndSet(true))
throw new IllegalStateException("Do not call myMethod twice")
}
}
答案 2 :(得分:0)
我对AtomicBoolean的需求感到有些困惑。因为你正在使用它,你应该做正确的事情并编写测试。非常好。但是,在JVM上测试线程代码非常困难(即使没有JVM的障碍,在其他语言中也不是特别容易)。
幸运的是,在您的情况下可能会有一个更简单的解决方案。看起来您可能正在尝试检测特定方法何时被意外同时使用。您是否可以阻止使用它?例如:
class MyObject {
def myMethod() {
synchronized {
.. stuff in here is serialized by the Hoare Monitor
}
}
}
有效的替代策略是在专门设计的模块中隔离顺序行为。这是actor模式背后的一般原则,也是更通用的CSP代数(在Occam,Go,Limbo中使用,并通过JCSP API在JVM上可用)。测试顺序代码通常要容易得多,因此这些模式可以帮助您将任务划分为可管理的块。
有四个并发失败,仅靠单独测试无法消除,关于I wrote an article a while ago。