我在一些帖子中读到使用JUnit测试并发性并不理想,但我现在别无选择。我刚遇到一个我无法解释的异常。
我在一个测试中进行了总结:
什么可能导致这种行为?
注意:我不时会得到例外。代码有一些不相关的东西,但我把它留在那里以防我错过了什么。 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());
}
答案 0 :(得分:2)
您无法在多个线程中的results
方法中添加ArrayList
Runnable.run()
,而无需在其周围进行同步。
断言失败消息显示尽管对N_THREADS
进行了add()
次调用,但由于并发争用条件,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()
但是我会把它拉到循环上面的变量中,除非它正在改变。