Java中Process类的使用与注意事项说明

 更新时间:2021年12月14日 09:45:17   作者:Kevin.Yang  
这篇文章主要介绍了Java中Process类的使用与注意事项说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

Process类的使用与注意事项说明

1、在项目开发中

经常会遇到调用其它程序功能的业务需求,在java中通常有两种实现方法

Runtime runtime = Runtime.getRuntime();
Process p = runtime.exec(cmd);
Process p=new ProcessBuilder(cmd).start();

2、在这里就需要认识一下process类

process是一个抽象的类,它包含6个抽象的方法

abstract public OutputStream getOutputStream();
abstract public InputStream getInputStream();
abstract public InputStream getErrorStream();
abstract public int waitFor() throws InterruptedException;
abstract public int exitValue();
abstract public void destroy();

process类提供获取子进程的输入流、子进程的输出流、子进程的错误流、等待进程完成、检查进程的推出状态以及销毁进程的方法;在这里需要提及的是创建的子进程没有自己的控制台或终端,其所有的io操作都是通过(输入流、输出流、错误流)重定向到父进程中。

3、来说说今天业务需求[waitfor()]:

我需要在linux下首先将一个文件copy到指定的文件夹下面,之后需要将该文件夹下面的文件加入指定的jar中,那么问题就来了,必须保证其先后顺序,也就书说再执行第二个命令的时候第一个命令必须完成。

    public void cmd(String cmd){
        try {
            Process ps= Runtime.getRuntime().exec(cmd); 
        } catch (Exception e) {
            logger.info(e.getMessage(),e);
        }
    }

main函数如下:

public static void main(String[] args){
     String copy="cp -rf "+source+" "+target;
     String jar="jar -uvf "+jar+" "+file;
     cmd(copy);
     cmd(jar);
}

但是结果是新生成的jar中压根没有新加入的文件,但是文件确实copy到了指定的文件夹中,也就是谁两个命令都执行了,问题的关键就是“异步”,这时候需要waitFor()的介入

    public void cmd(String cmd){
        try {
            Process ps= Runtime.getRuntime().exec(cmd); 
            ps.waitFor();
        } catch (Exception e) {
            logger.info(e.getMessage(),e);
        }
    }

那么问题就解决了!

4、前不久遇到一个奇怪的问题就是ajax调用没有返回值

我在service中实现了process的调用。

String[] commands = { commandGenerate,commandPublish};
        PrintWriter printWriter = response.getWriter();
        for (String comm : commands) {
            Runtime runtime = Runtime.getRuntime();
            try {
                logger.info("command is :{}",comm);
                Process process = runtime.exec(comm, null, null);
                BufferedInputStream inputStream = new BufferedInputStream(
                        process.getInputStream());
                BufferedReader bufferedReader = new BufferedReader(
                        new InputStreamReader(inputStream));
                String line;
                while (bufferedReader.read() != -1) {
                    line = bufferedReader.readLine();
                    System.out.println(line);
                }
                bufferedReader.close();
                inputStream.close();
                printWriter.println("success");
            } catch (IOException e) {
                logger.error(e.getMessage(), e);
                printWriter.println(e.getMessage());
            }
        }
        printWriter.flush();
        printWriter.close();

对应的controller为:

       State state = new State();
        String message="";
        try {
            message = missionService.syntax(taskName, response);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        state.setSuccess(true);
        state.setMessage(message.trim());
        return state;

打印state.getMessage()确实可以获得值,但是state返回就是空,刚开始以为是ajax的timeout时间的问题:修改了ajax的timeout时间仍然不行;将message直接赋值,然thread等待20s,结果是可以返回的,所以问题最终定为于service的这段实现。

原因分析:在上面提及了,process创建的子进程没有自己的控制台或终端,其所有的io操作都是通过(输入流、输出流、错误流)重定向到父进程中,如果该可执行程序的输入、输出或者错误输出比较多的话,而由于运行窗口的标准输入、输出等缓冲区有大小的限制,则可能导致子进程阻塞,甚至产生死锁,其解决方法就是在waitfor()方法之前读出窗口的标准输出、输出、错误缓冲区中的内容。

for (String comm : commands) {
            logger.info("the comm time is:"+new Date().getTime()+" the comm is:"+comm);
            Runtime runtime = Runtime.getRuntime();
            Process p=null;
            try {  
                 p = runtime.exec(comm ,null,null);         
                 final InputStream is1 = p.getInputStream();   
                 final InputStream is2 = p.getErrorStream();  
                 new Thread() {  
                    public void run() {  
                       BufferedReader br1 = new BufferedReader(new InputStreamReader(is1));  
                        try {  
                            String line1 = null;  
                            while ((line1 = br1.readLine()) != null) {  
                                  if (line1 != null){
                                      logger.info("p.getInputStream:"+line1);
                                      if(line1.indexOf("syntax check result:")!=-1){
                                          builder.append(line1);
                                      }
                                  }  
                              }  
                        } catch (IOException e) {  
                             e.printStackTrace();  
                        }  
                        finally{  
                             try {  
                               is1.close();  
                             } catch (IOException e) {  
                                e.printStackTrace();  
                            }  
                          }  
                        }  
                     }.start();  
                   new Thread() {   
                      public void  run() {   
                       BufferedReader br2 = new  BufferedReader(new  InputStreamReader(is2));   
                          try {   
                             String line2 = null ;   
                             while ((line2 = br2.readLine()) !=  null ) {   
                                  if (line2 != null){
                                  }  
                             }   
                           } catch (IOException e) {   
                                 e.printStackTrace();  
                           }   
                          finally{  
                             try {  
                                 is2.close();  
                             } catch (IOException e) {  
                                 e.printStackTrace();  
                             }  
                           }  
                        }   
                      }.start();                                                
                      p.waitFor();  
                      p.destroy();   
                    } catch (Exception e) {  
                            try{  
                                p.getErrorStream().close();  
                                p.getInputStream().close();  
                                p.getOutputStream().close();  
                                }  
                             catch(Exception ee){}  
                   }  
        }

java的process实例讲解

package cn.itcast.process;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;

public class ProcessTest implements Runnable{
 private Process process = null; 
 public ProcessTest() {
  try {
   process = Runtime.getRuntime().exec("java MyTest");
   new Thread(this).start();
   
  } catch (IOException e) {
   e.printStackTrace();
  }
 }
  
 public static void main(String[] args)  {
  ProcessTest processTest = new ProcessTest();
  processTest.send();
  
 }
 public void send()
 {
  OutputStream outputStream = process.getOutputStream();
  while(true)
  {
   try {
    outputStream.write("this is good\r\n".getBytes());
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }
 }
 public void run() {
  InputStream inputStream = process.getInputStream();
  BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
  String str = null;
  try {
   while(true)
   {
    str = bufferedReader.readLine();
    System.out.println(str);
   }   
  } catch (IOException e) {
   e.printStackTrace();
  }    
 }
}

理解下面这句话就能更加容易的理解上面的代码

在java程序中可以用Process类的实例对象来表示子进程,子进程的标准输入和输出不在连接到键盘和显示器,而是以管道流的形式连接到父进程的 一个输出流和输入流对象上-à好好理解这句代码就能看懂那个程序。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • JAVA对象中使用 static 和 String 基础探究

    JAVA对象中使用 static 和 String 基础探究

    这篇文章主要介绍了JAVA对象中使用static和String基础探究,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-09-09
  • Springboot 返回文件给前端的示例代码

    Springboot 返回文件给前端的示例代码

    这篇文章主要介绍了Springboot 返回文件给前端的示例代码,本文结合示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-07-07
  • 探索Java中的IP属地获取技术

    探索Java中的IP属地获取技术

    这篇文章主要为大家介绍了Java中的IP属地获取的技术探索,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-10-10
  • Spring中Transactional注解使用的心得(推荐)

    Spring中Transactional注解使用的心得(推荐)

    这篇文章主要介绍了Spring中Transactional注解使用的心得,事务是用来控制数据的ACID特性的,用于保证数据的正确性和完整性,需要的朋友可以参考下
    2022-10-10
  • Mybatis -如何处理clob类型数据

    Mybatis -如何处理clob类型数据

    这篇文章主要介绍了Mybatis 如何处理clob类型数据的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-06-06
  • hibernate查询缓存详细分析

    hibernate查询缓存详细分析

    这篇文章主要介绍了hibernate查询缓存详细分析,包括查询缓存配置方法及关闭二级缓存的详细介绍,需要的朋友参考下本文吧
    2017-09-09
  • 详解SpringBoot 统一后端返回格式的方法

    详解SpringBoot 统一后端返回格式的方法

    今天我们来聊一聊在基于SpringBoot前后端分离开发模式下,如何友好的返回统一的标准格式以及如何优雅的处理全局异常,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2022-05-05
  • Mybatis-Plus自动生成代码的实现示例

    Mybatis-Plus自动生成代码的实现示例

    在工作中,程序员很多时候都是在写类似的代码,可以使用自动生成代码,本文主要介绍了Mybatis-Plus自动生成代码的实现示例,具有一定的参考价值,感兴趣的可以了解一下
    2023-11-11
  • java去除字符串中的空格、回车、换行符、制表符的小例子

    java去除字符串中的空格、回车、换行符、制表符的小例子

    java去除字符串中的空格、回车、换行符、制表符的小例子,需要的朋友可以参考一下
    2013-06-06
  • 你真的懂java的日志系统吗

    你真的懂java的日志系统吗

    日志管理的第一件事,就是日志的收集,日志收集是开发者必备的技巧,不管是哪个开发语言,哪个开发平台,日志收集的插件都是有很多选择的,下面这篇文章主要给大家介绍了关于java日志系统的相关资料,需要的朋友可以参考下
    2022-02-02

最新评论