Maven构建在Surefire测试Test50后挂起问题求助
先梳理下你的问题背景:无代码变更,DB测试跑完Test50后就挂住了,Test51完全没启动;不管是用mvndebug -DforkCount=0 clean install还是普通的mvn clean install都出问题;换过Maven版本、Surefire插件版本和fork配置都没用,只有特定的Surefire配置组合能正常跑。结合你提供的线程dump和环境信息,我来帮你分析下原因和解决方案。
你的可用Surefire配置
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.21.0</version> <configuration> <forkMode>always</forkMode> <forkCount>1</forkCount> <reuseForks>true</reuseForks> <threadCount>1</threadCount> <parallel>suites</parallel> </configuration> </plugin>
线程Dump关键信息拆解
Main线程状态分析
"main@1" prio=5 tid=0x1 nid=NA waiting java.lang.Thread.State: WAITING at sun.misc.Unsafe.park(Unsafe.java:-1) at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175) at java.util.concurrent.FutureTask.awaitDone(FutureTask.java:429) at java.util.concurrent.FutureTask.get(FutureTask.java:191) at org.apache.maven.plugin.surefire.booterclient.ForkStarter.awaitResultsDone(ForkStarter.java:460) ...
Main线程卡在FutureTask.get()方法上,本质是它在等待Surefire启动的Fork测试进程返回完成信号,但这个Fork进程始终没发送信号,导致主线程无限等待。
后台Thread-17状态分析
"Thread-17@5301" daemon prio=5 tid=0x37 nid=NA runnable java.lang.Thread.State: RUNNABLE at java.io.FileInputStream.readBytes(FileInputStream.java:-1) at java.io.FileInputStream.read(FileInputStream.java:255) at java.io.BufferedInputStream.read1(BufferedInputStream.java:284) at java.io.BufferedInputStream.read(BufferedInputStream.java:345) - locked <0x14bb> (a java.io.BufferedInputStream) at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284) at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326) at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178) - locked <0x14bc> (a java.io.InputStreamReader) at java.io.InputStreamReader.read(InputStreamReader.java:184) ...
这个守护线程卡在读取输入流的操作上,结合你使用的Windows 10环境,基本可以确定是Fork进程的stdout/stderr缓冲区被占满,导致进程阻塞,无法向主线程发送完成信号——Windows系统对进程间流的处理逻辑和Unix不同,缓冲区满后会直接阻塞进程,不会自动扩容或处理。
针对性解决方案
1. 重定向测试输出到文件,解决流阻塞
这是最直接的修复方式,在你的可用Surefire配置中添加一行<redirectTestOutputToFile>true</redirectTestOutputToFile>,将测试输出写入文件,避免占满进程间的流缓冲区:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.21.0</version> <configuration> <forkMode>always</forkMode> <forkCount>1</forkCount> <reuseForks>true</reuseForks> <threadCount>1</threadCount> <parallel>suites</parallel> <redirectTestOutputToFile>true</redirectTestOutputToFile> </configuration> </plugin>
2. 检查Test50的数据库连接是否正确关闭
另一种可能是Test50执行完毕后,数据库连接未彻底关闭,导致Fork进程无法正常退出。你需要检查Test50的代码:
- 确保所有
Connection、Statement、ResultSet都在finally块中关闭,或使用try-with-resources语法自动关闭:
try (Connection conn = getDbConnection()) { // 执行数据库操作 } catch (SQLException e) { // 异常处理逻辑 }
- 也可以查看MySQL连接池状态,确认是否有未释放的连接占用资源。
3. 升级Surefire版本,规避旧版本Windows兼容bug
你当前使用的Surefire 2.21.0是较老版本,在Windows的fork机制上可能存在已知bug。尝试升级到3.0.0及以上的稳定版本,同时禁用进程复用(避免资源泄漏):
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>3.0.0-M7</version> <configuration> <forkCount>1</forkCount> <reuseForks>false</reuseForks> <redirectTestOutputToFile>true</redirectTestOutputToFile> </configuration> </plugin>
4. 排查Windows文件句柄泄漏
如果测试中涉及大量文件操作,可能导致文件句柄泄漏,进而阻塞流读取。可以通过Windows任务管理器查看进程的句柄数,确认是否有异常增长;同时检查测试代码中的文件流,确保所有流都已正确关闭。
内容的提问来源于stack exchange,提问作者Paul C. R.

