我必须编写一个单元测试来引发竞争条件,以便我可以测试我是否可能在以后解决问题。 问题是竞争条件很少发生,可能是因为我的计算机只有两个核心。
代码如下:
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(因为我们想要将它初始化为lazy,如前所述)。 现在,如果线程A进入该方法,然后调度程序在它运行initDateTime()之前就停止它。线程B现在运行getColonTime(),看到datetime仍为null并初始化它。 datetime.colonTime为null,因此执行第二个if块,datetime.colonTime获取StringBuilder的值。 如果调度程序停止此行和return语句之间的线程并恢复线程A,则会发生以下情况: 由于A在调用initDateTime之前就已停止,因此A现在调用initDateTime(),它将重置日期时间对象,再次将datetime.colonTime设置为null。线程A然后将进入第二个if块,但调度程序将在datetime.colonTime = sb.toString()之前中断A;叫做。作为结论,dateTime.colonTime仍为null。 现在,调度程序恢复B,方法返回null。
我试图通过让一些线程调用getColonTime()到MyDateTime的单个(最终)实例来激发竞争条件,但它只在一些极少数情况下失败:( 有关如何编写JUnit“测试”的任何提示吗?
答案 0 :(得分:7)
正如您所提到的,竞争条件非常难以一致地重现。但是,平均法则适合您。如果你创建一个你希望失败的测试,可能是一百次,然后让它发生一千次,你可能会在你的旧代码中相当一致地捕获错误。因此,为了与TDD原则保持一致,您应该按照以前的方式开始使用代码,进行测试迭代足够的次数以便始终针对旧代码失败,然后更改为新代码并确保它不会失败
答案 1 :(得分:5)
您可以查看Thread Weaver,或者可能有其他框架来测试多线程代码。我没有使用它,但Users' Guide看起来好像是为这种测试而设计的。
答案 2 :(得分:1)
我知道这篇文章已经很老了但是我遇到了类似的情况。我倾向于做的是通过睡眠来支持竞争条件。
在你的情况下,我会做类似
的事情 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竞争条件的好方法。分享的任何建议?
谢谢