我正在编写一个小程序,使用PsExec.exe
启动的cmd ProcessBuilder
来复制和安装联网PC上的应用程序(需要安装的PC数量可能不同于5至50)。
如果我按顺序为每台PC启动ProcessBuilder
,程序运行正常。
然而,为了加快速度,我想实现某种形式的 MultiThreading ,这可以让我同时安装5台PC(一批“5”Processbuilder
个进程“批量”直到所有PC都已安装)。
我在考虑将固定线程池与Callable接口结合使用(如果执行成功我必须评估)。
PsExec
使用的代码是:
ProcessBuilder
现在我已经阅读了一些关于如何实现Callable的信息,我想将我的 // Start iterating over all PC in the list:
for(String pc : pcList)
{
counter++;
logger.info("Starting the installation of remote pc: " + pc);
updateMessage("Starting the installation of remote pc: " + pc);
int exitVal = 99;
logger.debug("Exit Value set to 99");
try
{
ProcessBuilder pB = new ProcessBuilder();
pB.command("cmd", "/c",
"\""+psExecPath+"\"" + " \\\\" + pc + userName + userPassword + " -c" + " -f" + " -h" + " -n 60 " +
"\""+forumViewerPath+"\"" + " -q "+ forumAddress + remotePath + "-overwrite");
logger.debug(pB.command().toString());
pB.redirectError();
Process p = pB.start();
InputStream stErr = p.getErrorStream();
InputStreamReader esr = new InputStreamReader(stErr);
BufferedReader bre = new BufferedReader(esr);
String line = null;
line = bre.readLine();
while (line != null)
{
if(!line.equals(""))
logger.info(line);
line = bre.readLine();
}
exitVal = p.waitFor();
} catch (IOException ex)
{
logger.info("Exception occurred during installation of PC: \n"+pc+"\n "+ ex);
notInstalledPc.add(pc);
}
if(exitVal != 0)
{
notInstalledPc.add(pc);
ret = exitVal;
updateMessage("");
updateMessage("The remote pc: " + pc + " was not installed");
logger.info("The remote pc: " + pc + " was not installed. The error message returned was: \n"+getError(exitVal) + "\nProcess exit code was: " + exitVal);
}
else
{
updateMessage("");
updateMessage("The remote pc: " + pc + " was succesfully installed");
logger.info("The remote pc: " + pc + " was succesfully installed");
}
括在Callable接口中,然后提交所有任务以便在for循环中运行。
我是在正确的轨道上吗?
答案 0 :(得分:0)
你一定可以这样做。我想您想使用Callable而不是runnable来获取exitVal
的结果?
您的线程之间似乎没有任何共享数据,所以我认为您应该没问题。既然你甚至知道你要制作多少个Callables就可以创建一个Callables集合然后再做
List<Future<SomeType>> results = pool.invokeAll(collection)
这样可以更轻松地处理您的结果。在决定是否使用线程池时,您需要弄清楚的最重要的事情是,如果程序在线程仍在运行时终止,该怎么办;你是否必须完成你在线程中所做的事情,你是否需要无缝处理错误等。
查看java threadpools doc:https://docs.oracle.com/javase/tutorial/essential/concurrency/pools.html 或搜索网络,有大量关于何时使用线程池的帖子/博客。
但似乎你正走在正确的轨道上!
答案 1 :(得分:0)
感谢您的回复!它绝对让我走上正轨。我最终实现了这样:
ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(5); //NEW
List<Future<List<String>>> resultList = new ArrayList<>();
updateMessage("Starting the installation of all remote pc entered...");
// Start iterating over all PC in the list:
for(String pc : pcList)
{
counter++;
logger.debug("Starting the installation of remote pc: " + pc);
psExe p = new psExe(pc);
Future<List<String>> result = executor.submit(p);//NEW
resultList.add(result);
}
for(Future<List<String>> future : resultList)
{.......
在最后一个for循环中,我读取了我的操作结果并将其写在屏幕上或根据返回的结果进行操作。
我还有几个问题,因为我不太清楚:
1 - 如果我有20个PC并且在我的第一个For循环中将所有可调用线程提交到池中,我是否正确地获得它将只启动5个线程(线程池大小= 5)但是所有线程都已经创建并且处于等待状态,只有在第一个运行的线程完成并返回结果值后,下一个将自动启动,直到所有PC完成?
2 - 与我使用的方法(for循环中的submit())相比,使用invokeall()有什么区别(优点)?
再次感谢您的帮助......我真的很喜欢这个Java的东西!! ; - )