首先,这是我的代码:
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脚本,它将启动/停止远程服务器上的虚拟机(VMWARE).该脚本在命令行中运行,此代码也是如此.问题是,我讨厌如何使用一个线程(让它等待脚本响应,如进一步解释的那样)来完成这样的工作.我不得不这样做,因为BufferedReader.readline()和proc.waitFor()都会永远挂起.
从cmd运行时,该脚本很难执行.从服务器验证验证并执行实际脚本,它停止30秒到1分钟.从我从调试中看到的,当readline开始从脚本中接收到这些延迟时,它就会挂起.
我也很确定这不是内存问题,因为我在任何调试会话中都没有任何OOM错误.
现在我明白Process.waitFor()要求我从错误流和常规流中刷新缓冲区才能工作,这就是为什么我不使用它(我需要输出来管理VM特定的错误,证书问题)等).
我想知道是否有人可以向我解释为什么它会挂起,如果有一种方法可以使用典型的readline()而不必让它如此难以挂起.即使脚本应该已经结束了一段时间,它仍然挂起(我试图同时运行java应用程序和cmd命令使用我在java应用程序中使用的完全相同的东西,让它运行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在我的情况下按顺序获取它们的信息).
无论如何,多亏了你的所有答案,尤其是Miserable Variable,因为他提到了线程.
解决方法:
在开始从errorStream中读取之前,您当前正在等待从inputStream完成读取.如果进程在stdout之前写入stderr,那么你可能会遇到死锁情况.
尝试从并发运行的线程中读取两个流.当你在它时,也删除proc.getOutputStream().close();.它不应该影响行为,但也不需要.
标签:java,multithreading,powershell,vmware
来源: https://codeday.me/bug/20190725/1537146.html