I read in a few posts that using JUnit to test concurrency is not ideal but I have no choice for now. I have just encountered an exception that I can’t explain.
I run a test where, in summary:
- I submit 1000 runnables to an executor
- each runnable adds an element to a list
- I wait for the executor termination
- JUnit tells me the list only has 999 elements
- no exception is printed in the runnable catch block
What could cause that behavior?
Note: I only get the exception from time to time. The code has some non related stuff but I left it there in case I missed something. XXXQuery is an enum.
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());
}
You cannot add to the
resultsArrayListin yourRunnable.run()method in multiple threads without synchronizing around it.The assertion failed message is showing that although
N_THREADScalls toadd()were made, theArrayListgot fewer entries because of concurrency race conditions.I would use a final array instead of a list. Something like:
Also, I don’t quite get the
XXXQuery.values()but I’d pull that into a variable above the loop unless it is changing.