正常来说java调用shell命令就是用

String[] cmdAry = new String[]{"/bin/bash","-c",cmd}
Runtime.getRuntime().exec(cmdAry);

实际上就是创建个子进程去执行这个命令。

 

问题来了: 如果我执行下面这句命令

exp system/manager buffer=64000  file=/home/oracle/beifen/beifen.dmp  FULL=Y

这种输出日志量特别大的命令,就会出现卡死,一直不动,后来了解到 子进程产生的输出日志都会写到窗口里,因为窗口有缓存大小限制,

到达一定程度时就会卡死,导致死锁,后来百度了其他作者的资料才发现,这种直接调用exec用法是不好的,数据量小可能体现不出来,

数据量大的时候 就会直接缓存爆满 子进程就会卡死,所以我们可以创建2个线程来消费子进程运行shell命令产生的日志,正确用法如下

public class TestController {

    @GetMapping("/exp")
    public void addHomePage(String cmd) throws InterruptedException, IOException {
        //创建子进程调用shell命令
        new MyThread(cmd).start();
    }
}

class MyThread extends Thread {
    String cmd;
    MyThread(String cmd)
    {
        this.cmd = cmd;
    }
public void run(){ Process proc = null; try {
       String[] cmdAry = new String[]{"/bin/bash","-c",cmd} proc
= Runtime.getRuntime().exec(cmdAry); } catch (IOException e) { e.printStackTrace(); } //接收子进程的汇报信息和错误信息,避免阻塞 new StreamGobbler(proc.getInputStream(),"INFO").start(); new StreamGobbler(proc.getErrorStream(),"ERROR").start(); //获取子进程执行结果状态 int status= 0; try { status = proc.waitFor(); } catch (InterruptedException e) { e.printStackTrace(); } if (status == 0){ System.out.println("执行完毕"); }else System.out.println("执行失败"); //销毁子进程 proc.destroy(); } } class StreamGobbler extends Thread { InputStream is; String type; StreamGobbler(InputStream is, String type) { this.is = is; this.type = type; } public void run() { try { InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr); String line=null; while ( (line = br.readLine()) != null) System.out.println(type + ">" + line); } catch (IOException ioe) { ioe.printStackTrace(); } } }

这样就可以了  记得以后调用shell命令都用这种形式

posted on 2021-06-11 17:09  菜霸  阅读(978)  评论(0编辑  收藏  举报