执行shell命令时永远挂起(Java)

时间:2010-07-19 20:38:10

标签: java ejb

令人讨厌的代码块如下。代码几乎总是有效,但有时它会永远挂起。该应用程序是一个EJB计时器bean。

实际上,它只挂了一次,我无法重现它。它的生产工作近两年没有任何问题。但是,在测试应用程序的更新版本时,计时器在运行几天后就冻结了,并且从未在上次运行时释放数据库锁。日志清楚地表明它冻结在下面的代码块中的某处。它正在运行的命令是'chmod'。

public void shellExec(String cmd, File workDir) {
    String s = null;
    try {
        Process p = Runtime.getRuntime().exec(cmd, null, workDir);
        int i = p.waitFor();
        if (i == 0){
            BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
            // read the output from the command
            while ((s = stdInput.readLine()) != null) {
                logger.debug(s);
            }
        }
        else {
            BufferedReader stdErr = new BufferedReader(new InputStreamReader(p.getErrorStream()));
            // read the output from the command
            while ((s = stdErr.readLine()) != null) {
                logger.debug(s);
            }
        }
    } catch (Exception e) {
        logger.debug(e);
    }
}

我对修改此代码犹豫不决,因为它已经过测试并且已经正常工作了近两年。我也无法重现这个问题所以我不知道重写版本是否更好。但是,很明显它可以挂起,我不知道可能性是什么。

从谷歌搜索问题,似乎该代码块是执行shell命令的标准。该代码是否存在任何已知问题?有没有人知道一种好的方法来确保它会抛出异常而不是挂起,考虑到我无法重现这个问题?

感谢。

2 个答案:

答案 0 :(得分:5)

您需要同时执行stdout / err 的消耗。否则,您将获得您看到的阻止行为。有关详细信息,请参阅this answer

答案 1 :(得分:2)

与使用stderr和stdout有关,这里有一个我经常使用的便利类:

import java.io.InputStream;
import java.io.OutputStream;

public final class Pipe implements Runnable {

    private final InputStream in;
    private final OutputStream out;

    public Pipe(InputStream in, OutputStream out) {
        this.in = in;
        this.out = out;
    }

    public static void pipe(Process process) {
        pipe(process.getInputStream(), System.out);
        pipe(process.getErrorStream(), System.err);
        pipe(System.in, process.getOutputStream());
    }

    public static void pipe(InputStream in, OutputStream out) {
        final Thread thread = new Thread(new Pipe(in, out));
        thread.setDaemon(true);
        thread.start();
    }

    public void run() {
        try {
            int i = -1;

            byte[] buf = new byte[1024];

            while ((i = in.read(buf)) != -1) {
                out.write(buf, 0, i);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

超级简单,没有任何额外的库就可以了。