JUnit 和并发:莫名其妙的错误



我在几篇文章中读到,使用 JUnit 测试并发性并不理想,但我现在别无选择。我刚刚遇到了一个我无法解释的异常。

我运行一个测试,总结一下:

  • 我向遗嘱执行人提交 1000 个可运行项
  • 每个可运行对象将一个元素添加到列表中
  • 我等待遗嘱执行人终止
  • JUnit告诉我列表只有999个元素
  • 在可运行的捕获块中打印无异常

什么可能导致这种行为?

注意:我只是不时收到异常。代码有一些不相关的东西,但我把它留在那里,以防我错过了什么。 XXXQuery是一个枚举。

public void testConcurrent() throws InterruptedException {
    final int N_THREADS = 1000;
    final XXXData xxxData = new AbstractXXXDataImpl();
    final List<QueryResult> results = new ArrayList<>();
    ExecutorService executor = Executors.newFixedThreadPool(N_THREADS);
    for (int i = 0; i < N_THREADS; i++) {
        final int j = i;
        executor.submit(new Runnable() {
            @Override
            public void run() {
                try {
                    results.add(xxxData.get(XXXQuery.values()[j % XXXQuery.values().length]));
                } catch (Exception e) {
                    System.out.println(e);
                }
            }
        });
    }
    executor.shutdown();
    executor.awaitTermination(10, TimeUnit.SECONDS);
    assertEquals(N_THREADS, results.size());
}

如果不围绕Runnable.run()方法进行同步,则无法在多个线程中向results ArrayList添加。

断言失败消息显示,尽管对add()进行了N_THREADS调用,但由于并发争用条件,ArrayList获得的条目较少。

我会使用最终数组而不是列表。 像这样:

final QueryResult[] results = new QueryResult[N_THREADS];
for (int i = 0; i < N_THREADS; i++) {
    ...
        public void run() {
            results[j] = data.get(Query.values()[j % Query.values().length]);
        }

另外,我不太明白XXXQuery.values()但我会将其拉到循环上方的变量中,除非它正在发生变化。

最新更新