Junit tests multithreading attention

background

An interesting observation occurred when testing a file conversion utility class. The same input was parsed correctly using the Main function, but Junit could not get the result. Miraculously, even if the Throwable was captured, the Throwable was not caught.

class Main { public static void main(String[] args) { String trxFileDir = args[0]; String targetDir = args[1]; boolean isDecode = Boolean.parseBoolean(args[2]); ParseMojo parseMojo = new ParseMojo(trxFileDir,targetDir,isDecode); parseMojo.execute(); }}Copy the code
@Test public void executeEncode() { String trxFileDir = "E:\\MAE\\code\\MyMojoParse\\src\\main\\resources\\inputFile\\";  String targetDir = "E:\\MAE\\code\\MyMojoParse\\src\\main\\resources\\outputFile\\"; boolean isEncode = true; ParseMojo parser = new ParseMojo(trxFileDir, targetDir, isEncode); parser.execute(); }Copy the code

Parsing tools support multithreading, the core code is as follows

		 Arrays.stream(trxFiles).forEach(trx -> PARSE_POOL.execute(() -> {
                    convertToBinaryFile(trx);
            }));
Copy the code

Speculate on possible causes

First of all, the current problem has nothing to do with business logic. It is suspected that there is a problem with multithreading and UT. Maybe when Junit is testing, the main thread will terminate, resulting in the termination of child threads.

Troubleshoot problems

Add print to view the break in the file

The print result is as follows:

Obviously, when the main process exits, the child process has not completed execution, and each execution has reached an inconsistent location

Question why

Analyze Junit source code

    public static void main(String args[]) {
        TestRunner aTestRunner = new TestRunner();
        try {
            TestResult r = aTestRunner.start(args);
            if (!r.wasSuccessful()) {
                System.exit(FAILURE_EXIT);
            }
            System.exit(SUCCESS_EXIT);
        } catch (Exception e) {
            System.err.println(e.getMessage());
            System.exit(EXCEPTION_EXIT);
        }
    }
Copy the code

This is the entry to the Junit run, and we can see that system.exit () is called regardless of whether the Junit test succeeds, and this method is used to terminate the currently running Java virtual machine. When status=0, it indicates that the program ends normally. When status=1, it indicates that the program exits abnormally. If the JVM is shut down, how do child threads run? So that’s the problem.

conclusion

When the test class is required to perform tasks for multiple threads, do not directly use Junit unit test, because the system may exit, resulting in abnormal interruption of the task.

Note that concurrent utility classes such as CountDownLatch and thread.join() ensure that all threads in the task complete.