Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/306.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Java中引发竞争条件_Java_Race Condition - Fatal编程技术网

在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获得了一些多线程调试支持。统计数据也在你这边:如果你足够频繁地重复一个测试,你肯定会偶尔遇到竞争条件:)另请参见