java Runtime.getRuntime().exec阻塞卡死问题解决

java | 2019-09-13 10:02:39

java中Runtime.getRuntime().exec是用来执行外部命令的,我就是用这个来执行spark程序spark-submit,我的场景就是定时任务调用这个代码来执行spark任务,但是总是遇到Runtime.getRuntime().exec一直等待不结束,导致程序不往下执行,定时任务的线程也一直卡着不动。


1.阻塞原因分析

用jps命令查看到了阻塞到的进程,再用jstack查看进程信息,截取了最后的信息,因为jstack是从后往前分析的。

# jps
8023 SparkSubmit
#jstack 8023
"main" #1 prio=5 os_prio=0 tid=0x00007f66fc010000 nid=0x1f7f runnable [0x00007f6705ba6000]
   java.lang.Thread.State: RUNNABLE
at java.io.FileOutputStream.writeBytes(Native Method)
at java.io.FileOutputStream.write(FileOutputStream.java:326)
at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
- locked <0x00000005cbc49dc0> (a java.io.BufferedOutputStream)
at java.io.PrintStream.write(PrintStream.java:482)
- locked <0x00000005cbc49da0> (a java.io.PrintStream)

貌似是读取信息流导致的阻塞。


2.结合网上的信息是"错误输出流"和"错误输出流"导致的阻塞

具体原因-java程序给进程的输出流分配的缓冲区是很小的,有时候当进程输出信息很大的时候回导致缓冲区被填满,如果不及时处理程序会阻塞。如果程序没有对进程的输出流处理的会就会导致执行exec()的线程永远阻塞


3.解决问题

2.1第一种方法 命令行指定输出

spark-submit --class org.apache.spark.examples.SparkPi /opt/hadoop/spark-2.3.0-bin-hadoop2.7/examples/jars/spark-examples_2.11-2.3.0.jar 10 1>/dev/null 2>&1 &

这样就不需要你读取输出流,直接输出到不存在的地方,2>&1表示错误信息和前面的正常信息也一样输出到/dev/null。&表示后台运行


3.2第二种方法 用子进程读取输出流

读取输出流的多线程代码,可以公用重复使用,直接复制吧。

class InputStreamRunnable extends Thread {
    BufferedReader bReader = null;
    String type = null;
    public InputStreamRunnable(InputStream is, String _type) {
        try {
            bReader = new BufferedReader(new InputStreamReader(new BufferedInputStream(is), "UTF-8"));
            type = _type;
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
    public void run() {
        String line;
        int lineNum = 0;
        try {
            while ((line = bReader.readLine()) != null) {
                lineNum++;
                System.out.println(type+":"+line);
            }
            bReader.close();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}


然后修改Runtime.getRuntime().exec代码


Process process = Runtime.getRuntime().exec(commond.toString());
new InputStreamRunnable(process.getErrorStream(), "Error").start();
new InputStreamRunnable(process.getInputStream(), "Info").start();
boolean code = process.waitFor(30,TimeUnit.MINUTES);
logger.warn("spark 执行计算结果:code-" + code);
process.destroy();


再次测试发现所有的信息都打印出来了,阻塞问题也没有了。


登录后即可回复 登录 | 注册
    
关注编程学问公众号