首页 > 作文

使用Runtime 调用Process.waitfor导致的阻塞问题

更新时间:2023-04-04 02:56:20 阅读: 评论:0

目录
1. 关于runtime类的小知识2. runtime的几个重要的重载方法3. runtime的使用方式4. 卡死原因5. 解决方案6. runtime最优雅的调用方式

1. 关于runtime类的小知识

runtime.getruntime()可以取得当前jvm的运行时环境,这也是在java中唯一一个得到运行时环境的方法runtime中的exit方法是退出jvm

2. runtime的几个重要的重载方法

方法名作用exec(string command);在单独的进程中执行指定的字符串命令。exec(string command, string[] envp)在指定环境的单独进程中执行指定的字符串命令。exec(string[] cmdarray, string[] envp, file dir)在指定环境和工作目录的独立进程中执行指定的命令和变量exec(string command, string[] envp, file dir)在有指定环境和工作目录的独立进程中执行指定的字符串命令。

runtime类的重要的方法还有很多,简单列举几个

exit(int status):终止当前正在运行的 java 虚拟机freememory():返回 java 虚拟机中的空闲内存量。load(string filename): 加载作为动态库的指定文件名。loadlibrary(string libname): 加载具有指定库名的动态库。

3. runtime的使用方式

错误的使用exitvalue()

  public static void main(string[] args) throws ioexception {        string command = "ping www.baidu.com";        process process = runtime.getruntime().exec(command);        int i = process.exitvalue();        system.out.println("字进程退出值:"+i);    }

输出:

exception in thread “main” java.lang.illegalthreadstateexception: process has not exited
at java.lang.processimpl.exitvalue(processimpl.java:443)
at com.lirong.think.runtime.processutils.main(processutils.java:26)

原因:

exitvalue()方法是非阻塞的,在调用这个方法时cmd命令并没有返回所以引起异常。阻塞形式的方法是waitfor,它会一直等待外部命令执行完毕,然后返回执行的结果。

修改后的版本:

  public static void main(string[] args) throws ioexception {        string command = "javac";        process process = runtime.getruntime().exec(command);        process.waitfor();        process.destroy();        int i = process.exitvalue();        system.out.println("字进程退出值:"+i);    }

此版本已然可以正常运行,但当主线程和子线程有很多交互的时候还是会出问题,会出现卡死的情况。

4. 卡死原因

主进程中调用runtime.exec会创建一个子进程,用于执行cmd命令。子进程创建后会和主进程分别独立运行。因为主进程需要等待脚本执行完成,然后对命令返回值或输出进行处理,所以这里主进程调用process.waitfor等待子进程完成。运行此cmd命令可以知道:子进程执行过程就是打印信息。主进程中可以通过process.getinputstream和process.geterrorstream获取并处理。这时候子进程不断向主进程发生数据,而主进程调用process.waitfor后已挂起。当前子进程和主进程之间的缓冲区塞满后,子进程不能继续写数据,然后也会挂起。这样子进程等待主进程读取数据,主进程等待子进程结束,两个进程相互等待,最终导致死锁。

5. 解决方案

不断的读取消耗缓冲区的数据,以至子进程不会挂起,下面是具体代码:

/** * @author lirong * @desc cmd命令测试 * @date 2019/06/13 20:50 */@slf4jpublic class processutils {    public static void main(string[] args) throws ioexception, interruptedexception {        string command = "ping www.baidu.com";        process process = runtime.getruntime().exec(command);        readstreaminfo(process.getinputstream(), process.geterrorstream());        int exit = process.waitfor();        process.destroy();        if (exit == 0) {            log.debug("子进程正常完成");        } el {            log.debug("子进程异常结束");        }    }    猪的吉祥语/**     * 读取runtime.exec运行子进程的输入流 和 异常流     * @param inputstreams 输入流     */    public static void readstreaminfo(inputstream... inputstreams){        executorrvice executorrvice = executors.newfixedthreadpool(inputstreams.length);        for (inputstream in : inputstreams) {    建材市场招商方案        executorrvice.execute(new mythread (in));        }        executorrvice.shutdown();    }}/** * @author lirong * @desc * @date 2019/06/13 21:25 */@slf4jpublic class mythread implements runnable {    private inputstream in;    public mythread(inputstream in){        this.in = in;    }    @override    public void run() {        try{            bufferedreader br = new bufferedreader(new inputstreamreader(in, "gbk"));            string line = null;            while((line = br.readline())!=null){                log.debug(" inputstream: " + line);            }        }catch (ioexception e){            e.printstacktrace();        }finally {            try {                in.clo();            } catch (ioexception e) {                e.printstacktrace();            }        }    }}

写到这里大家以为都结束了哇,并没有,哈哈哈,真实的生成环境总能给你带来很多神奇的问题,runtime不仅可以直接调用cmd执行命令,还可以调用其他.exe程序执行命令。

所以纵使你读取了缓冲区的数据,你的程序依然可能会被卡死,因为有可能你的缓冲区根本就没有数据,而是你的.exe程序卡主了。嗯,所以为你以防万一,你还需要设置超时。

6. runtime最优雅的调用方式

/** * @author lirong * @desc * @date 2019/06/13 20:50 */@slf4jpublic class proc女生当兵要求essutils {  操作系统有哪些 /**     * @param timeout 超时时长     * @param filedir 所运行程序路径     * @param command 程序所要执行的命令     * 运行一个外部命令,返回状态.若超过指定的超时时间,抛出timeoutexception     */    public static int executeprocess(final long timeout, file filedir, final string[] command)            throws ioexception, interruptedexception, timeoutexception {        process process = runtime.getruntime().exec(command, null, filedir);        worker worker = new worker(process);        worker.start();        try {            worker.join(timeout);            if (worker.exit != null){                return worker.exit;            } el{                throw new timeoutexception();            }        } catch (interruptedexception ex) {            worker.interrupt();            thread.currentthread().interrupt();            throw ex;        }        finally {            process.destroy();        }    }        private static class worker extends thread {        private final process process;        private integer exit;        private worker(process process) {            this.process = process;        }        @override        public void run() {            inputstream errorstream = null;            inputstream inputstream = null;            try {                errorstream = process.geterrorstream();                inputstream = process.getinputstream();                readstreaminfo(errorstream, inputstream);                exit = process.waitfor();                process.destroy();                if (exit == 0) {                    log.debug("子进程正常完成")什么是中位数;                } el {                    log.debug("子进程异常结束");                }            } catch (interruptedexception ignore) {                return;            }        }    }    /**     * 读取runtime.exec运行子进程的输入流 和 异常流     * @param inputstreams 输入流     */    public static void readstreaminfo(inputstream... inputstreams){        executorrvice executorrvice = executors.newfixedthreadpool(inputstreams.length);        for (inputstream in : inputstreams) {            executorrvice.execute(new mythread(in));        }        executorrvice.shutdown();    }}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持www.887551.com。

本文发布于:2023-04-04 02:56:18,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/zuowen/a12996939dc265e51857df0df8001376.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

本文word下载地址:使用Runtime 调用Process.waitfor导致的阻塞问题.doc

本文 PDF 下载地址:使用Runtime 调用Process.waitfor导致的阻塞问题.pdf

标签:进程   命令   方法   缓冲区
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图