一次java使用Runtime.getRuntime().exec()调用Python因事务的导致程序卡死的经历

因事务导致的问题

在前几天的一个项目中使用Runtime.getRuntime().exec()调用Python脚本,伪代码如下:

    @RequestMapping("/XXX")
    @Transactional
    public xxx XXX(@RequestBody X x) {
        ...  
  	Runtime.getRuntime().exec()
        return xxx;
    }

在加了事务之后在其过程中,添加了Runtime.getRuntime().exec(),在运行的时候直接卡死不动。最终原因是事务锁定了mysql,然而调用脚本的时候其脚本也对数据库有所操作,导致数据无法写入,一直卡着不动弹,最后自己将事务取消之后立马,运行通畅但是脚本运行的数据有是另一种情况。如下

Runtime.getRuntime().exec() 输出流阻塞问题

在调用完成之后一直读不到其错误信息,一直摸不到头脑,有一次应该也是因为这个原因导致程序运行阻塞,一直卡着不动。最终查询资料发现正确的数据流和错误的数据流都应该被处理。经过处理问题终于得到解决。

有时候我们可能需要调用系统外部的某个程序,此时就可以用Runtime.getRuntime().exec()来调用,他会生成一个新的进程去运行调用的程序。
此方法返回一个java.lang.Process对象,该对象可以得到之前开启的进程的运行结果,还可以操作进程的输入输出流。

Process对象有以下几个方法:
  1、destroy()      杀死这个子进程
  2、exitValue()      得到进程运行结束后的返回状态
  3、waitFor()       得到进程运行结束后的返回状态,如果进程未运行完毕则等待知道执行完毕
  4、getInputStream()  得到进程的标准输出信息流
  5、getErrorStream()  得到进程的错误输出信息流
  6、getOutputStream() 得到进程的输入流

现在来讲讲exitValue(),当线程没有执行完毕时调用此方法会跑出IllegalThreadStateException异常,最直接的解决方法就是用waitFor()方法代替。

但是waitFor()方法也有很明显的弊端,因为java程序给进程的输出流分配的缓冲区是很小的,有时候当进程输出信息很大的时候回导致缓冲区被填满,如果不及时处理程序会阻塞。如果程序没有对进程的输出流处理的会就会导致执行exec()的线程永远阻塞,进程也不会执行下去直到输出流被处理或者java程序结束。
解决的方法就是处理缓冲区中的信息,开两个线程分别去处理标准输出流和错误输出流。

public class ExecTest {

    public static void main(String[] args) throws IOException, InterruptedException {
      String cmd = "cmd /c dir D:\\";
      final Process process = Runtime.getRuntime().exec(cmd);
      printMessage(process.getInputStream());
      printMessage(process.getErrorStream());
      int value = process.waitFor();
      System.out.println(value);
    }

    private static void printMessage(final InputStream input) {
      new Thread(new Runnable() {
         public void run() {
            BufferedReader bf = new BufferedReader(new InputStreamReader(input));
            String line = null;
             try {
                while((line=bf.readLine())!=null) {
                    System.out.println(line);
                }
             } catch (IOException e) {
                e.printStackTrace();
             }
         }
      }).start();
    }
}

参考链接:https://blog.csdn.net/u010414589/article/details/77725896


🐞标题:一次java使用Runtime.getRuntime().exec()调用Python因事务的导致程序卡死的经历
👽作者:ruige
🐾地址:https://jjdhhc.com/articles/2020/07/31/1596204935732.html
🙏感恩:谢谢您的打赏与支持!中间图片是我的微信公众号,扫码关注哦!
支付宝支付 微信公众号 微信支付