繁体   English   中英

Mockito when() 并行 stream 意外结果

[英]Mockito when() in parallel stream unexpected result

我在我们的一项测试中调查了 Mockito 的行为,但我不理解它的行为。 以下代码片段显示了相同的行为:

@Test
public void test(){
    var mymock = Mockito.mock(Object.class);
    var l = List.of(1,2,3);
    l.parallelStream().forEach(val -> {
        int finalI = val;
        doAnswer(invocationOnMock -> {
            log.info("{}",finalI);
            return null;
        }).when(mymock).toString();
        mymock.toString();
    });
}

我期待的 output 是按某种顺序打印的 1,2,3(不是 nessaseraly 排序的):

我收到的 output:

2
2
2

为什么我得到这个 output?

这是一个经典的竞争条件:您的并行 ZF7B44CFFAFD5C52223D5498196C8A2E7BZ 并行执行forEach lambda 三次。 在这种情况下,所有三个线程都设法执行了doAnswer()调用,然后它们中的任何一个都到达了mymock.toString()行。 恰好val=2的执行恰好最后运行。 令人高兴的是,Mockito 是相当线程安全的,因此您不会只是抛出异常。

您的情况可能发生的一种方式是,如果线程碰巧像这样运行:

  1. 主线程:调用l.parallelStream().forEach() ,它产生 3 个线程,其val等于 1、2 和 3
  2. val=1 线程:执行finalI=val ,在这个线程中给它一个值 1
  3. val=2 线程:执行finalI=val ,在这个线程中给它一个值 2
  4. val=3 线程:执行finalI=val ,在这个线程中给它一个值 3
  5. val=3 线程:调用doAnswer(...)这使得将来调用mymock.toString()打印出3
  6. val=1 线程:调用doAnswer(...)这使得将来调用mymock.toString()打印出1
  7. val=2 线程:调用doAnswer(...)这使得将来调用mymock.toString()打印出2
  8. val=1 线程:调用mymock.toString() ,打印出2
  9. val=2 线程:调用mymock.toString() ,打印出2
  10. val=3 线程:调用mymock.toString() ,打印出2

请注意,这不一定按顺序发生,甚至不一定按此顺序发生:

  • 其中某些部分实际上可能同时发生在处理器的不同内核中。
  • 虽然单个线程中的任何步骤总是按顺序运行,但它们可能在任何其他线程的任何步骤之前、之后或交错运行。

因为线程是并行运行的,而您没有安排任何东西来管理它,所以无法保证这些调用发生的顺序:您的 output 可能很容易是1 1 1 , 1 2 3 , 3 2 13 2 21 1 3等。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM