在Java中激起竞争条件

时间:2011-09-16 14:15:34

标签: java race-condition

我必须编写一个单元测试来引发竞争条件,以便我可以测试我是否可能在以后解决问题。 问题是竞争条件很少发生,可能是因为我的计算机只有两个核心。

代码如下:

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“测试”的任何提示吗?

3 个答案:

答案 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竞争条件的好方法。分享的任何建议?

谢谢