Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/313.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Process.waitFor()和Readline挂起_Java_Multithreading_Powershell_Vmware - Fatal编程技术网

Java Process.waitFor()和Readline挂起

Java Process.waitFor()和Readline挂起,java,multithreading,powershell,vmware,Java,Multithreading,Powershell,Vmware,首先,这是我的代码: import java.io.*; import java.util.Date; import com.banctecmtl.ca.vlp.shared.exceptions.*; public class PowershellTest implements Runnable { public static final String PATH_TO_SCRIPT = "C:\\Scripts\\ScriptTest.ps1"; public static final

首先,这是我的代码:

import java.io.*;
import java.util.Date;

import com.banctecmtl.ca.vlp.shared.exceptions.*;

public class PowershellTest implements Runnable {

public static final String PATH_TO_SCRIPT = "C:\\Scripts\\ScriptTest.ps1";
public static final String SERVER_IP = "XX.XX.XX.XXX";
public static final String MACHINE_TO_MOD = "MachineTest";

/**
 * @param args
 * @throws OperationException 
 */
public static void main(String[] args) throws OperationException {

    new PowershellTest().run();

}

public PowershellTest(){}

@Override
public synchronized void run() {
    String input = "";
    String error = "";

    boolean isHanging = false;

    try {

        Runtime runtime = Runtime.getRuntime();
        Process proc = runtime.exec("powershell -file " + PATH_TO_SCRIPT +" "+ SERVER_IP +" "+ MACHINE_TO_MOD);
        proc.getOutputStream().close();
        InputStream inputstream = proc.getInputStream();
        InputStreamReader inputstreamreader = new InputStreamReader(inputstream);
        BufferedReader bufferedreader = new BufferedReader(inputstreamreader);

        proc.waitFor();

        String line;
        while (!isHanging && (line = bufferedreader.readLine()) != null) {
            input += (line + "\n");
            Date date = new Date();
            while(!bufferedreader.ready()){

                this.wait(1000);
                //if its been more then 1 minute since a line has been read, its hanging. 
                if(new Date().getTime() - date.getTime() >= 60000){

                    isHanging = true;
                    break;

                }
            }
        }

        inputstream.close();
        inputstream = proc.getErrorStream();
        inputstreamreader = new InputStreamReader(inputstream);
        bufferedreader = new BufferedReader(inputstreamreader);
        isHanging = false;

        while (!isHanging && (line = bufferedreader.readLine()) != null) {
            error += (line + "\n");
            Date date = new Date();
            while(!bufferedreader.ready()){

                this.wait(1000);
                //if its been more then 1 minute since a line has been read, its hanging. 
                if(new Date().getTime() - date.getTime() >= 60000){

                    isHanging = true;
                    break;

                }
            }
        }
        inputstream.close();

        proc.destroy();

    } catch (IOException e) {
        //throw new OperationException("File IO problem.", e);
    } catch (InterruptedException e) {
        //throw new OperationException("Script thread problem.",e);
    }
    System.out.println("Error : " + error + "\nInput : " + input);
}
}

我当前正在尝试运行powershell脚本,该脚本将启动/停止远程服务器上的vm(VMWARE)脚本在命令行中工作,这段代码也是如此。问题是,我讨厌这样的工作必须使用线程(并让它等待脚本响应,如进一步解释的那样)。我不得不这么做,因为BufferedReader.readline()和proc.waitFor()都永远挂起

从cmd运行脚本时,执行时间很长。从使用服务器验证身份验证并执行实际脚本开始,它将暂停30秒到1分钟。从调试中我看到,当readline开始接收来自脚本的延迟时,它会挂起

我也很确定这不是内存问题,因为我在任何调试会话中都没有任何OOM错误

现在我知道Process.waitFor()需要我从错误流和常规流中刷新缓冲区才能工作,这就是我不使用它的主要原因(我需要输出来管理特定于VM的错误、证书问题等)

我想知道是否有人可以向我解释为什么它会挂起,以及是否有一种方法可以只使用典型的readline(),而不必挂得那么硬。即使脚本应该在一段时间后结束,它仍然挂起(我尝试使用与java应用程序中使用的完全相同的东西同时运行java应用程序和cmd命令,让它运行1小时,没有任何效果)。它不仅仅卡在while循环中,readline()是挂起的地方

另外,这是一个测试版本,没有接近最终代码的地方,所以请恕我直言:这应该是一个常量,这是无用的,等等。我稍后会清理代码。显然,在我的代码中,IP不是XX.XX.XX.XXX

无论是解释还是建议如何修复,我们都将不胜感激

顺便说一句,这是我目前使用的脚本:

Add-PSSnapin vmware.vimautomation.core

Connect-VIServer -server $args[0]

Start-VM -VM "MachineTest"
如果你需要更多的细节,我会尽力提供

提前感谢您的帮助

编辑:我之前还使用要求较低的脚本测试了代码,该脚本的任务是获取文件的内容并将其打印出来。由于无需等待即可获取信息,因此readline()运行良好。因此,我相当确定问题在于脚本执行的等待时间

还有,请原谅我的错误,英语不是我的主要语言

提前感谢您的帮助

编辑2:因为我不能回答我自己的问题:

以下是我使用线程后的“最终”代码:

import java.io.*;

public class PowershellTest implements Runnable {

public InputStream is;

public PowershellTest(InputStream newIs){

    this.is = newIs;
}

@Override
public synchronized void run() {
    String input = "";
    String error = "";

    try {


        InputStreamReader inputstreamreader = new InputStreamReader(is);
        BufferedReader bufferedreader = new BufferedReader(inputstreamreader);

        String line;
        while ((line = bufferedreader.readLine()) != null) {
            input += (line + "\n");

        }

        is.close();

    } catch (IOException e) {
        //throw new OperationException("File IO problem.", e);
    }
    System.out.println("Error : " + error + "\nInput : " + input);
}

}
主线程只需创建并启动2个线程(PowerShellTest实例),1个使用errorStream,1个使用inputStream

我相信我第一次编写应用程序时犯了一个愚蠢的错误,并在反复修改代码时以某种方式修复了它。它仍然需要5-6分钟的时间来运行,这与我以前的代码相似,如果不长的话(这是合乎逻辑的,因为在我的例子中,errorStream和inputStream是按顺序获取信息的)


无论如何,多亏了你的回答,尤其是可怜的Variable对线程的提示。

首先,在读完流之前,不要调用
waitFor()
。我强烈建议您查看
ProcessBuilder
,而不是简单地使用
Runtime.exec
,并自行拆分命令,而不是依赖Java来完成:

ProcessBuilder pb = new ProcessBuilder("powershell", "-file", PATH_TO_SCRIPT,
        SERVER_IP, MACHINE_TO_MOD);
pb.redirectErrorStream(true); // merge stdout and stderr
Process proc = pb.start();

redirectErrorStream
将错误输出合并到正常输出中,因此您只需读取
proc.getInputStream()
。然后,您应该能够读取该流直到EOF,然后调用当前正在等待从
inputStream
完成读取的
proc.waitFor()
,然后再开始从
errorStream
读取。如果进程在
stdout
之前写入其
stderr
,则可能会陷入死锁状态


尝试从并发运行的线程读取两个流。同时,还要删除
proc.getOutputStream().close()。它不应该影响行为,但也不是必需的

我将尝试不关闭
outputStream
并在两个不同的并发线程中读取
inputStream
errorStream
。我已经尝试不关闭outputStream,但没有结果,我将很快尝试使用StreamGobbler执行线程(实际上,在我们键入时对其进行测试)。此外,outputstream没有理由被打开,而且只会带来问题,据我在相当多的帖子上读到的,因为无论如何我没有其他东西要发送。事实上,这是有效的。我开始认为,当我第一次编写应用程序时,我可能只是犯了一个小错误,在重新编写代码时,我以某种方式修复了这个错误。仅供参考,我没有使用StreamGobbler,只有普通InputStream。我仍然关闭输出。无论如何,谢谢!我将把我的评论转换成一个答案,这样你就可以接受它。我几乎尝试过这个解决方案(没有重定向错误流)。出于某种原因,当我的errorStream中明显存在错误时,waiTFor不会给我任何错误消息(返回值为0)。我相信这是因为我检索到了VMWARE错误,而不是powershell错误,但我可能错了。无论如何,我没有发现ProcessBuilder和Runtime.exec在行为上有任何区别,但我将对此进行研究。无论如何,谢谢你,很多有用的建议
waitFor
返回本机进程的退出代码,因此您是否获得有意义的内容取决于您正在执行的程序……如果没有任何输出/错误,流将永远无法读取任何内容。