首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >process.waitFor()抛出IllegalThreadStateException

process.waitFor()抛出IllegalThreadStateException
EN

Stack Overflow用户
提问于 2022-01-06 15:58:58
回答 2查看 346关注 0票数 1

环境

Windows 10 Java 1.8

过程

代码语言:javascript
运行
复制
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

我的代码

代码语言:javascript
运行
复制
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;

我找不到这个问题的根本原因。

注意:--我在同一台机器上用类似的演示实例尝试了这个过程,它运行得很好。

请帮我解决这个问题谢谢。

EN

回答 2

Stack Overflow用户

发布于 2022-10-05 15:16:36

如果您的问题是由Windows ProcessBuilder退出代码259错误引起的,那么就有一些解决办法:您需要做的就是确保您的子进程不会退出状态代码259,并且Windows不会报告java.lang.IllegalThreadStateException

通过使用Runtime.getRuntime().exec(cmd)ProcessBuilder(cmd)执行以下命令,您可以轻松地再现此问题

代码语言:javascript
运行
复制
String[] cmd = {"cmd.exe /c exit /b 259"};

如果您已经为子进程编写了代码,那么只需编辑您的代码,以便退出代码永远不会设置为259。

如果您还没有为子进程编写代码,那么一个相当麻烦的解决方法是用一个"CMD.EXE“和mini脚本包装您的Java子进程启动,该脚本将非零子进程退出返回到退出代码0或1:

代码语言:javascript
运行
复制
String[] fixed = new String[] { "cmd.exe", "/c", 
        "(call "+String.join(" ", cmd)+ ") || (echo !!! DETECTED ERROR!!! && exit 1)" };

注释:我不是CMD方面的专家。上面的修复肯定不会对某些命令或标点符号(例如带有引号/空格等的命令或标点符号)起作用,而且由于它在CMD.EXE环境下运行,结果可能会与调用的JVM直接启动不同。

下面是一个可以用来测试的示例类:

代码语言:javascript
运行
复制
/** 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)"
        };
    }
}
票数 0
EN

Stack Overflow用户

发布于 2022-10-10 11:57:01

你的问题有两部分:

  1. JDK有一个错误,当Windows进程返回259退出代码时,会引发异常。
  2. 传递给ProcessBuilder的命令在不应该的情况下退出代码为259。

依次处理每一点:

  1. JDK中的bug是由Process.waitFor()特定于Windows的实现中的以下有缺陷的逻辑引起的:首先,它一直等到进程退出。然后,它调用exitValue()从进程中获取退出值。但是不幸的是,exitValue()获得了退出值,然后检查它是否是一个特殊值,表示进程尚未退出。因为waitFor()知道进程已经退出,所以它应该直接获得退出值,而不是调用这个方法来进行不必要的检查。希望JDK开发人员很快就能修复这个错误。
  2. 您应该使用命令行版本的7-zip,7z.exe,它以一组定义良好的出口值退出(因此它永远不会返回259)。
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70609906

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档