Java线程和时间:Nedd对实现的看法

时间:2013-12-06 07:02:17

标签: java multithreading

所以我正在运行一个用Java启动C ++程序的Process。 C ++程序在OutputStream上写入一些数据,并从Java中读取该流。

实施看起来像这样:

    ....
    ProcessBuilder pb = new ProcessBuilder(filepath);
    Process process;
    InputStream processStream;
    try {
        Process p = pb.start();
        ProcessOutput processOutput = new ProcessOutput(p.getInputStream());
        processOutput.run();
        return processOutput.getRequestString();
    } catch (IOException e1) {
        LOG.error(e1.getMessage());
    }

变量filepath是指向可执行C ++程序的String。 ProcessOutput类是一个Thread,它读取InputStream并将其转换为String,稍后可以通过ProcessOutput.getRequestString()检索它。

应用程序似乎行为正常,但我现在好奇我是否可以通过构建解决方案的方式出现任何计时问题。是否有可能在我调用processOutput.getRequestString()时进程尚未完成或者是否阻止执行直到进程完成?

我现在正在开发Java一段时间,但进程/线程仍让我感到困惑。如果有人看到这个实现的一些问题,我很乐意改进它。

按要求处理ProcessOutput类:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

public class ProcessOutput extends Thread {

    private InputStream inputStream;
    private String requestString;

    public ProcessOutput(InputStream inputStream) {
        this.inputStream = inputStream;
        setDaemon(true);
    }

    public void run() {
        BufferedReader br = null;
        StringBuilder sb = new StringBuilder();

        String line;
        try {

            br = new BufferedReader(new InputStreamReader(this.inputStream));
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        requestString = sb.toString();
    }

    public String getRequestString() {
        return requestString;
    }

}

编辑:正如评论中提到的zapl,我没有从使用Thread获得任何东西,因为应用程序依赖于进程的结果而必须等待它结束反正。

3 个答案:

答案 0 :(得分:2)

您可以调用process.waitFor()以使代码等待进程完成。但是,作为一个建议,如果不消耗错误/输出流,直接调用进程不是一个好习惯。你可以使用apache commons exec库,这很方便。

答案 1 :(得分:1)

你可以在processOutput线程上添加一个join(),这样它就等待ProcessBuilder Thread完成它的执行,并确保你得到所需的请求String。

答案 2 :(得分:1)

你可以使用一些同步器,如倒计时或循环障碍等。 我添加倒计时实现如下。如果您认为在某些情况下可能需要一段时间,我认为在单独的线程中运行IO逻辑没有坏处。在getRequestString调用中,如果时间过长,您可以决定如何处理该方案。

public class ProcessOutput {
    private final InputStream inputStream;
    final CountDownLatch latch = new CountDownLatch(1);

    public ProcessOutput(InputStream inputStream) {
        this.inputStream = inputStream;
    }

    public String getRequestString(final long timeoutMilliSeconds) throws InterruptedException {
        StreamReader reader = new StreamReader();
        new Thread(reader).start();
        latch.await(timeoutMilliSeconds,TimeUnit.MILLISECONDS);
        //You can check if requestString not yet set or null after waiting for timeout throw some application exception to tell the client that its taking too long.
        return reader.getRequestString();
    }

    private class StreamReader implements Runnable {

        String requestString;
        @Override
        public void run() {
            BufferedReader br = null;
            StringBuilder sb = new StringBuilder();

            String line;
            try {

                br = new BufferedReader(new InputStreamReader(inputStream));
                while ((line = br.readLine()) != null) {
                    sb.append(line);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (br != null) {
                    try {
                        br.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            requestString = sb.toString();
            //Work done now
            latch.countDown();
        }

        public String getRequestString() {
            return requestString;
        } ;
    }
}