在Java程序上实现多线程
我正在编写一个小Java程序,它使用cmd中的在Java程序上实现多线程,java,multithreading,Java,Multithreading,我正在编写一个小Java程序,它使用cmd中的PsExec.exe通过ProcessBuilder启动,在联网PC上复制并安装应用程序(需要安装的PC数量可能从5到50不等) 如果我依次为每台电脑启动了ProcessBuilder,该程序运行良好 然而,为了加快速度,我想实现某种形式的多线程,它允许我同时安装5台PC(一批5个Processbuilder进程,直到所有PC都安装完毕) 我在考虑将固定线程池与可调用接口结合使用(每次执行PsExec都会返回一个值,该值指示执行是否成功,并且我必须评
PsExec.exe
通过ProcessBuilder
启动,在联网PC上复制并安装应用程序(需要安装的PC数量可能从5到50不等)
如果我依次为每台电脑启动了ProcessBuilder
,该程序运行良好
然而,为了加快速度,我想实现某种形式的多线程,它允许我同时安装5台PC(一批5个Processbuilder
进程,直到所有PC都安装完毕)
我在考虑将固定线程池与可调用接口结合使用(每次执行PsExec
都会返回一个值,该值指示执行是否成功,并且我必须评估该值)
用于Process Builder的代码为:
// 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的信息,我想将我的ProcessBuilder
放在一个可调用的界面中,然后提交for循环中运行的所有任务
我走对了吗?你肯定能做到。我想您希望使用Callable而不是runnable来获取您的
exitVal
的结果
您的线程之间似乎没有任何共享数据,所以我认为您应该没事。因为您甚至知道要生成多少个可调用项,所以可以创建一个可调用项集合,然后
List<Future<SomeType>> results = pool.invokeAll(collection)
List results=pool.invokeAll(集合)
这样可以更容易地处理结果。在决定是否使用线程池时,您需要弄清楚的最重要的事情可能是,如果程序在线程仍在运行时终止,该怎么办;您是否必须完成线程中的工作,是否需要无缝处理错误等
查看java线程池文档:
或者在网上搜索,有大量关于何时使用或不使用线程池的帖子/博客
但看起来你走对了路 谢谢您的回复!这肯定让我走上了正确的道路。我最终实现了如下:
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)
{.......
ThreadPoolExecutor executor=(ThreadPoolExecutor)Executors.newFixedThreadPool(5)//新的
List resultList=new ArrayList();
updateMessage(“开始安装所有输入的远程pc…”);
//开始迭代列表中的所有PC:
用于(字符串pc:pcList)
{
计数器++;
logger.debug(“开始安装远程pc:+pc”);
psExe p=新的psExe(pc);
未来结果=executor.submit(p);//新建
结果列表。添加(结果);
}
for(未来:结果列表)
{.......
在最后一个for循环中,我读取操作的结果,并将其写入屏幕或根据返回的结果进行操作
我还有几个问题,因为我还不太清楚:
1-如果我有20个PC,并在我的第一个For循环中将所有可调用线程提交到池中,那么我是否正确地得到只启动5个线程的消息(threadpool size=5)但是,所有线程都将被创建并处于等待状态,只有在第一个运行的线程完成并返回结果值后,下一个线程才会自动启动,直到所有PC机完成
2-与我使用的方法(for循环中的submit()相比,您建议使用invokeall()有什么区别(优势)
再次感谢您的帮助…我真的很喜欢这个Java东西!!;-)太好了,这正是我想要的,干得好!至于您的问题:1:当您创建一个大小为5的fixedthreadpool时,无论您是否有5个任务分配到池中,都会启动5个线程。如果有5个以上的任务,它们只需按照您的说法等待即可。2:invokeAll是sim这是因为你似乎有这么少的任务,但是如果你有更多的任务,你可能应该考虑使用提交或一个时间可变的变量,以即时处理结果。如果要在每个线程完成后立即获得一个结果,而不必等待池中的所有线程完成,那么实现这一点的最佳方法是什么?我可以告诉每个线程在完成后立即通知我结果吗?谢谢