`

java调用外部程序挂起原因

    博客分类:
  • Java
阅读更多
转自:http://blog.csdn.net/fh13760184/archive/2009/05/06/4153734.aspx

Process p = Runtime.getRuntime().exec("my command ...");
int c = p.waitFor();
if (c != 0)
{
    System.out.prinln("处理失败");

    BufferedReader br = new BufferedReader(new InputStreamReader(p.getErrorStream()));

    for (String line = br.readLine(); line != null; line = br.readLine())
    {
        System.out.println(line);
    }    
}

  

当执行的外部命令没有任何输出的时候,这段代码运行正常,但如果执行的外部命令有输出的时候,这段程序就会挂起,估计是因为流没有被读取导致了堵塞,于是把代码改为
  
 public void test() throws IOException, InterruptedException
    {
        Process p = Runtime.getRuntime().exec("command...");
        String errorMsg = readInputStream(p.getErrorStream());
        String outputMsg = readInputStream(p.getInputStream());

        int c = p.waitFor();
        if (c != 0)
        {
            System.out.println("处理失败:" + errorMsg);
        }else
        {//print command output
            System.out.println(outputMsg);
        }
    }

    private  String readInputStream(InputStream is) throws IOException
    {
        BufferedReader br = new BufferedReader(new InputStreamReader(is));

        StringBuffer lines = new StringBuffer();
        for (String line = br.readLine(); line != null; line = br.readLine())
        {
            lines.append(line);
        }
        return lines.toString();
    }


但是我在windows上执行这样的调用的时候却总是在while那里被堵塞了,结果造成 程序在执行了一会后不再执行,这里从官方的参考文档中我们可以看到这是由于缓冲区的问题,由于java进程没有清空 程序写到缓冲区的内容,结果导致程序一直在等待。在网上也查找了很多这样的问题,不过说的都是使用单独的线程来进行控制,我也尝试过很多网是所说的方法,可一直没起什么作用。下面就是我的解决方法了,注意到上述代码中的红色部分了么?这里就是关键,我把它改成如下结果就可以正常运行了。

InputStream is = process.getErrorStream(); // 获取ffmpeg进程的输出流


我把它改成获取错误流这样进程就不会被堵塞了,而我之前一直想的是同样的命令我手动调用的时候可以完成,而java调用却总是完成不了,一直认为是getInputStream的缓冲区没有被清空,不过问题确实是缓冲区的内容没有被清空,但不是getInputStream的,而是getErrorStream的缓冲区,这样问题就得到解决了。所以我们在遇到java调用外部程序而导致线程阻塞的时候,可以考虑使用两个线程来同时清空process获取的两个输入流,如下这段程序:
……
Process process = Runtime.getRuntime.exec(command); // 调用外部程序
final InputStream is1 = process.getInputStream();
new Thread(new Runnable() {
    public void run() {
        BufferedReader br = new Buffered(new InputStreamReader(is));
        while(br.readLine() != null) ;
    }
}.start(); // 启动单独的线程来清空process.getInputStream()的缓冲区
InputStream is2 = process.getErrorStream();
BufferedReader br2 = new Buffered(new InputStreamReader(is2));
StringBuilder buf = new StringBuilder(); // 保存输出结果流
String line = null;
while((line = br.readLine()) != null) buf.append(line); // 循环等待ffmpeg进程结束
System.out.println("输出结果为:" + buf);
……


    通过这样我们使用一个线程来读取process.getInputStream()的输出流,使用另外一个线程来获取 process.getErrorStream()的输出流,这样我们就可以保证缓冲区得到及时的清空而不担心线程被阻塞了。当然根据需要你也可以保留 process.getInputStream()流中的内容,这个就看调用的程序的处理了。我在windows下调用FFmpeg程序进行视频转换的时候就是通过这样来解决线程被堵塞的问题的,呵呵~
分享到:
评论
1 楼 shellfj 2011-07-21  
说得挺好~~~

相关推荐

    调用系统文件管理器

    这个例子就是关于如何在Android应用程序中调用系统自带的文件管理器。以下是对这个主题的详细解释: 一、Android系统文件管理器介绍 Android系统自带的文件管理器是用于查看、组织和操作设备上存储的文件和目录的...

    《java学习》-Java web开发async机制学习.zip

    Java Web的异步处理机制就是为了缓解这个问题,它允许服务器不立即返回响应,而是先将请求挂起,去处理其他请求,待后台任务完成后再回调通知客户端。 1. **Servlet 3.0 异步处理**: Servlet 3.0引入了异步处理...

    java笔试题目以及部分答案

    sleep() 方法将线程挂起一段时间,而 wait() 方法将线程挂起,直到其他线程调用 notify() 或 notifyAll() 方法。 13. Java 有没有 goto? Java 语言中没有 goto 语句,但是可以使用 break、continue 和 return ...

    在程序中实现对java源文件编译的3种方法.pdf

    这种方法无需调用外部命令,所有的编译操作都在Java虚拟机内部完成。 **核心步骤**: 1. **获取编译器实例**:通过`ToolProvider.getSystemJavaCompiler()`方法获得当前JVM中的`JavaCompiler`实例。 2. **构建编译...

    Java的基础入门教程

    - `suspend <threadid>`:挂起指定线程。 - `resume <threadid>`:恢复指定线程。 - `where <id>`:显示指定线程的调用堆栈。 - `print <id>`:打印变量值。 - `dump <id>`:保存变量值到文件。 - `stopin ...

    2013年10月-Java语言程序设计(一)试题答案.doc

    - `resume()`方法用于恢复之前被挂起的线程。 9. **包导入** - 要使用输入/输出操作的程序,必须要导入`java.io`包。 - **知识点扩展**: - Java标准库中的`java.io`包包含了大量用于处理输入输出操作的类和...

    java阻塞i/o与非阻塞i/o控制

    当一个线程调用read或write方法时,如果数据尚未准备好,那么这个线程会被挂起,即进入阻塞状态,直到数据准备就绪。这种方式简单直观,但存在效率问题,因为线程在等待数据期间无法执行其他任务。 例如,服务器...

    JAVA一个计算机类的程序.doc

    其他方法如`turnOnPc()`, `turnOffPc()`, 和 `hitchPc()`模拟了打开、关闭和挂起计算机的操作。这些方法接收参数,并返回表示操作结果的字符串。 此外,我们看到了类有两个构造函数。一个默认构造函数(无参构造...

    超级有影响力霸气的Java面试题大全文档

    当应用程序在对象上调用了一个需要花费很长时间来执行的方法,并且不希望让程序等待方法的返回时,就应该使用异步编程,在很多情况下采用异步途径往往更有效率。 20、abstract class和interface有什么区别? ...

    JAVA的IO与NIO

    它们主要负责程序与外部世界的通信,包括读取文件、网络数据交换等。本文将深入探讨NIO(New Input/Output)与IO的区别,以及NIO中的关键概念——Channel、Buffer以及它们如何协同工作。 知识点1:NIO与IO的区别 IO...

    java精通程度应该会什么

    - **阻塞/非阻塞**: 阻塞I/O在等待时会挂起线程,而非阻塞I/O则不会。 - **同步/异步**: 同步I/O是指I/O操作完成之前线程会被阻塞,而异步I/O则是非阻塞的。 - **四种模型**: 阻塞I/O、非阻塞I/O、多路复用I/O...

    java结束进程的实例代码

    应妥善处理这些输出,避免程序因未捕获的异常而挂起。 2. **进程管理**:执行的外部进程可能会创建子进程。如果需要确保所有相关进程都被结束,可能需要使用更复杂的逻辑来跟踪和终止它们。 3. **权限问题**:终止...

    java面试题(线程和JSP及EJB部分).pdf

    - 挂起:线程被阻塞或等待资源。 - 结束:线程执行完毕。 9. **`synchronized`与`Lock`的比较**: - 相同:都提供线程同步,防止数据竞争。 - 不同:`Lock`提供更细粒度的控制,需手动获取和释放锁,且在`...

    面试题java

    - 线程有就绪、运行、synchronized阻塞、wait/sleep挂起和结束等状态。 - 线程状态转换受`synchronized`、`wait()`和`notify()`等方法影响。 6. **面向对象的特征**: - 封装:隐藏实现细节,提供公共接口供外部...

    JAVA_C#程序员面试宝典3

    - 新建、就绪、运行、睡眠、等待、挂起、恢复、阻塞和死亡。 22. **串行化**: - 用于持久化对象,标记为`Serializable`的类可以被序列化。注意循环引用可能导致问题。 23. **线程同步**: - 通过`synchronized...

    Java面试宝典2010版

    ### Java面试宝典2010版知识点解析 #### 一、Java基础部分 ##### 1、一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制? - **答案**:可以包括多个类,但是只能有一个公共(`public`)类,并且...

Global site tag (gtag.js) - Google Analytics