【问题标题】:ProcessBuilder does not stopProcessBuilder 不会停止
【发布时间】:2011-09-26 21:24:26
【问题描述】:

我正在尝试使用 Linux 下的 ProcessBuilder 类将 mp3 文件解码为 wav 文件。由于某种原因,该过程不会停止,因此我必须手动取消它。

有人可以给我一个提示吗?我认为引用的代码很容易重现:

import java.io.*;

public class Test {
 public static void main(String[] args) {
     try {
         Process lameProcess = new ProcessBuilder("lame", "--decode", "test.mp3", "-").start();
         InputStream is = lameProcess.getInputStream();
         FileOutputStream fileOutput = new FileOutputStream("test.wav");
         DataOutputStream dataOutput = new DataOutputStream(fileOutput);


         byte[] buf = new byte[32 * 1024];
         int nRead = 0;
         int counter = 0;
         while((nRead = is.read(buf)) != -1) {
             dataOutput.write(buf, 0, buf.length);
         }

         is.close();
         fileOutput.close();

     }
     catch (Exception e) {
         e.printStackTrace();
     }
 }
}

jstack 的输出

"main" prio=10 tid=0x0000000002588800 nid=0x247a runnable [0x00007f17e2761000]
   java.lang.Thread.State: RUNNABLE
    at java.io.FileInputStream.readBytes(Native Method)
    at java.io.FileInputStream.read(FileInputStream.java:236)
    at java.io.BufferedInputStream.fill(BufferedInputStream.java:235)
    at java.io.BufferedInputStream.read1(BufferedInputStream.java:275)
    at java.io.BufferedInputStream.read(BufferedInputStream.java:334)
    - locked <0x00000000eb5b1660> (a java.io.BufferedInputStream)
    at java.io.FilterInputStream.read(FilterInputStream.java:107)
    at Test.main(Test.java:17)

【问题讨论】:

  • 不应该在某一时刻在 Process 对象上调用 waitFor() 方法吗?
  • 挂在哪里?使用jstack &lt;pid&gt;kill -3 &lt;pid&gt; 获取线程转储。
  • 看起来你正在拨打read() 电话。你的外部进程终止了吗?
  • 只需添加 pb.redirecterrorstream(true)

标签: java processbuilder


【解决方案1】:

您需要排空进程的输出(通过getInputStream())和错误(通过getErrorStream())流,否则可能会阻塞。

引用Process documentation

由于部分原生平台只为标准输入输出流提供有限的缓冲区大小,未能及时写入子进程的输入流或读取输出流可能会导致子进程阻塞,甚至死锁。

(适用于错误和输出流)

您可能需要在不同线程中耗尽每个流,因为每个流在没有数据时可能会阻塞。

【讨论】:

  • 或者您可以使用ProcessBuilder.redirectErrorStream() 将流合并为一个,让生活更轻松。
  • +1。我的建议是使用java.util.concurrent 生成一个新线程并将感兴趣的InputStream 传递给新线程以进行累积。您可以使用 Apache IO commons 在一行中完成:IOUtils.toString(inputStream, YOUR_CONSOLE_CHARSET);
  • @Jon7 redirectErrorStream() 在这种特殊情况下可能不是一个好主意 - 输出流用作 WAVE 输出,并且其中混入错误消息会损坏 WAV 文件。
【解决方案2】:

使用像LAMEOnJ 这样的 LAME Java 包装器可能会容易得多。这样您就可以避免产生进程,并且您可以与 lame 进行交互,就好像它是一个 Java 库一样。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-11-02
    • 2010-11-05
    • 2013-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多