在Java中引发竞争条件
我需要编写一个单元测试,它会引发一个竞争条件,这样我就可以测试我以后是否修复了这个问题。 问题是竞争条件很少发生,可能是因为我的计算机只有两个内核 代码如下所示:在Java中引发竞争条件,java,race-condition,Java,Race Condition,我需要编写一个单元测试,它会引发一个竞争条件,这样我就可以测试我以后是否修复了这个问题。 问题是竞争条件很少发生,可能是因为我的计算机只有两个内核 代码如下所示: class MyDateTime { String getColonTime() { // datetime is some kind of lazy caching variable declared somewhere(does not matter) if (datetime == null) {
class MyDateTime {
String getColonTime() {
// datetime is some kind of lazy caching variable declared somewhere(does not matter)
if (datetime == null) {
initDateTime(); //Uses lazy to initlialize variable, takes some time
}
// Colon time stores hh:mm as string
if (datetime.colonTime == null) {
StringBuilder sb = new StringBuilder();
//Now do some steps to build the hh:mm string
//...
//set colon time
datetime.colonTime = sb.toString();
}
return datetime.colonTime;
}
}
说明:
initDateTime将一个新实例分配给dateTime,因此dateTime.colonTime之后为null(正如我前面所述,我们希望将其初始化为惰性)。
现在,如果线程A进入该方法,然后调度程序在运行initDateTime()之前停止该方法。线程B现在运行ST getColonTime(),发现datetime仍然为null并初始化它。datetime.colonTime为null,因此执行第二个if块,datetime.colonTime获取StringBuilder的值。
如果调度程序停止此行和return语句之间的线程并恢复线程A,则会发生以下情况:
由于在调用initDateTime之前停止了,A现在调用initDateTime(),这将类似于重置datetime对象,并再次将datetime.colonTime设置为null。然后线程A将进入第二个if块,但调度程序将在datetime.colonTime=sb.toString()之前中断A;被称为。总之,dateTime.colonTime仍然为空。
现在,调度器恢复B,方法返回null
我试图通过让多个线程对MyDateTime的一个(最终)实例调用getColonTime()来引发竞争条件,但它只在一些非常罕见的情况下失败:(
有关于如何编写JUnit“测试”的提示吗正如你所提到的,种族条件很难一致地再现。然而,平均法则站在你这边。如果你创建了一个测试,你预计失败百分之一,然后让它发生一千次,你可能会在旧代码中相当一致地发现错误。因此,与TDD保持一致原则上,你应该像以前那样从代码开始,提出一个测试迭代足够多次,以使旧代码一致失败,然后换成新代码,确保它不会失败。你可以看看,或者可能有其他框架来测试多线程代码。我没有使用过它,但看起来好像它是我的我知道这篇文章很老了,但我也面临着类似的情况。我倾向于用睡眠来支持比赛条件 在你的情况下,我会这样做
class MyDateTime {
String getColonTime() throws InterruptedException{
if (datetime == null) {
Thread.sleep(new Random().nextInt(100); //Wait to enhance the chances that multiple threads enter here and reset colonTime.
initDateTime();
}
Thread.sleep(new Random().nextInt(100); //Wait to enhance the chances that colonTime stays null for a while.
if (datetime.colonTime == null) {
StringBuilder sb = new StringBuilder();
datetime.colonTime = sb.toString();
}
Thread.sleep(new Random().nextInt(100); //Wait to favour reset of colonTime by another thread in the meantime.
return datetime.colonTime;
}
}
但很明显,这会很快变得混乱。我希望有某种方法可以迫使调度程序在给定一些“断点”的情况下探索所有路径
由于这篇文章有点陈旧,我想知道你是否找到了用Java测试竞争条件的好方法。有什么建议可以分享吗
谢谢你你可以先尝试使用调试器来激发竞争条件。例如,启动一个线程,在某个断点(如if之间)捕获它,然后启动另一个断点,依此类推。在你了解RC是如何发生的之后(似乎你现在一点都不知道)你可以编写一个成功的单元测试。我不知道如何才能到达
return datetime.colonTime;
并返回空值。你确定如何构建hh:mm字符串没有问题吗?也许可以将该代码添加到你的问题中,这样我们就可以看到了。我添加了一些额外的解释,解释了为什么会发生这种情况。不得不承认,这不是你的问题ry obviousI已经看到了它,但我不知道它有多合适。有经验吗?我试过thread weaver。如果你知道问题出在哪里,它非常适合测试。但是,你不能在一个方法的行上进行N x N测试(我在讨论组中问)。测试失败的概率很高,但要求的概率越高,测试运行的时间就越长。单元测试应该很快。(但我没有更好的主意。)正如我在接受的答案中所说,Thread weaver是一个很好的工具,我想现在还有其他工具。例如,如果我没记错的话,IntelliJ获得了一些多线程调试支持。统计数据也在你这边:如果你足够频繁地重复一个测试,你肯定会偶尔遇到竞争条件:)另请参见