环境
Windows 10 Java 1.8
过程
I am running a 7zip's zip task.
The process takes 2 to 3 hours to complete.
异常
java.lang.IllegalThreadStateException:进程尚未退出 在java.lang.ProcessImpl.exitValue(ProcessImpl.java:443) 在java.lang.ProcessImpl.waitFor(ProcessImpl.java:452at
我的代码
int exitValue = -1;
Process start = null;
try
{
ProcessBuilder processBuilder = new ProcessBuilder(commands);
start = processBuilder.start();
try(BufferedReader ipBuf = new BufferedReader(new InputStreamReader(start.getInputStream())))
{
String line = null;
while ((line = ipBuf.readLine()) != null)
{
LOGGER.info(line);
}
}
try(BufferedReader errBuf = new BufferedReader(new InputStreamReader(start.getErrorStream())))
{
String line;
while ((line = errBuf.readLine()) != null)
{
LOGGER.warning(line);
}
}
start.waitFor();
exitValue = start.exitValue();
}
finally
{
if (start != null)
{
start.destroy();
}
}
return exitValue;
我找不到这个问题的根本原因。
注意:--我在同一台机器上用类似的演示实例尝试了这个过程,它运行得很好。
请帮我解决这个问题谢谢。
发布于 2022-10-05 15:16:36
如果您的问题是由Windows ProcessBuilder退出代码259错误引起的,那么就有一些解决办法:您需要做的就是确保您的子进程不会退出状态代码259,并且Windows不会报告java.lang.IllegalThreadStateException
。
通过使用Runtime.getRuntime().exec(cmd)
或ProcessBuilder(cmd)
执行以下命令,您可以轻松地再现此问题
String[] cmd = {"cmd.exe /c exit /b 259"};
如果您已经为子进程编写了代码,那么只需编辑您的代码,以便退出代码永远不会设置为259。
如果您还没有为子进程编写代码,那么一个相当麻烦的解决方法是用一个"CMD.EXE“和mini脚本包装您的Java子进程启动,该脚本将非零子进程退出返回到退出代码0或1:
String[] fixed = new String[] { "cmd.exe", "/c",
"(call "+String.join(" ", cmd)+ ") || (echo !!! DETECTED ERROR!!! && exit 1)" };
注释:我不是CMD方面的专家。上面的修复肯定不会对某些命令或标点符号(例如带有引号/空格等的命令或标点符号)起作用,而且由于它在CMD.EXE环境下运行,结果可能会与调用的JVM直接启动不同。
下面是一个可以用来测试的示例类:
/** Examples to test with and without the fix:
java Status259 "cmd.exe /c exit /b 0"
java Status259 "cmd.exe /c exit /b 25"
java Status259 "cmd.exe /c exit /b 259"
java Status259 %JAVA_HOME%\bin\java -cp your.jar Status259$StatusXXX 0
java Status259 %JAVA_HOME%\bin\java -cp your.jar Status259$StatusXXX 33
java Status259 %JAVA_HOME%\bin\java -cp your.jar Status259$StatusXXX 259
*/
public class Status259 {
public static class StatusXXX {
public static void main(String ... args) {
int status = args.length > 0 ? Integer.parseInt(args[0]) : 0;
System.out.println("StatusXXX exit code: "+status);
System.exit(status);
}
}
public static int exec(String[] cmd) throws IOException, InterruptedException {
System.out.println("exec "+Arrays.toString(Objects.requireNonNull(cmd)));
ProcessBuilder pb = new ProcessBuilder(cmd);
// No STDERR => merge to STDOUT - or call redirectError(File)
pb.redirectErrorStream(true);
Process p = pb.start();
// send sub-process STDOUT to the Java stdout stream
try(var stdo = p.getInputStream()) {
stdo.transferTo(System.out);
}
int rc = p.waitFor();
System.out.println("exec() END pid="+p.pid()+" CODE "+rc +' '+(rc == 0 ? "OK":"**** ERROR ****"));
return rc;
}
public static void main(String ... args) throws IOException, InterruptedException {
// COMMENT OUT NEXT LINE TO SEE EFFECT OF DIRECT LAUNCH:
args = fixStatus259(args);
int rc = exec(args);
System.exit(rc);
}
private static String[] fixStatus259(String[] cmd) {
System.out.println("fixStatus259 "+Arrays.toString(cmd));
return new String[] {
"cmd.exe", "/c",
"(call "+String.join(" ", cmd)+ ") || (echo !!! DETECTED ERROR!!! && exit 1)"
};
}
}
发布于 2022-10-10 11:57:01
你的问题有两部分:
依次处理每一点:
exitValue()
从进程中获取退出值。但是不幸的是,exitValue()
获得了退出值,然后检查它是否是一个特殊值,表示进程尚未退出。因为waitFor()
知道进程已经退出,所以它应该直接获得退出值,而不是调用这个方法来进行不必要的检查。希望JDK开发人员很快就能修复这个错误。7z.exe
,它以一组定义良好的出口值退出(因此它永远不会返回259)。https://stackoverflow.com/questions/70609906
复制相似问题