Java:在单独的进程中运行Callable

时间:2008-12-04 23:25:09

标签: java multithreading process stdout stdin

鉴于x的实例Callable<T>,如何在单独的流程中运行x,以便我可以重定向流程的标准输入和输出?例如,有没有办法从Process构建Callable?是否有标准Executor可以控制输入和输出?

[更新] Callable在新进程中执行而不是新线程并不重要。我想要的是将Callable实例放在“harness”中,以便我可以控制它的stdin / stdout。 AFAIK,这需要一个新的过程。

4 个答案:

答案 0 :(得分:2)

更一般地说:

  

给定一个使用全局变量A和B的Callable实例x,如何同时运行x使得x看到A和B的自定义值,而不是A和B的“原始”值?

最好的答案是,不要使用全局变量。依赖注入这样的东西。扩展Callable并添加方法setStdIn,setStdOut(如果需要,还可以添加setStdErr)。

我知道这不是您正在寻找的答案,但我所看到的解决方案都需要一个新的流程,而您将Callable变为新流程的唯一方法是更改​​代码Callable所以它是可序列化的,或者提供一个类名,或者其他一些hack,所以不要做出会给你一个讨厌,脆弱的解决方案的改变,而是正确行事*

*“正确”是使用广泛接受的依赖注入模式来提供松散耦合。 YMMV

更新:回复评论1.这是您的新界面:

import java.io.InputStream;
import java.io.PrintStream;
import java.util.concurrent.Callable;


public interface MyCallable<V> extends Callable<V> {
  void setStdIn(InputStream in);
  void setStdOut(PrintStream out);  
}

你的任务看起来像是:

import java.io.InputStream;
import java.io.PrintStream;


public class CallableTask implements MyCallable<Object> {

    private InputStream in = System.in;
    private PrintStream out = System.out;

    public void setStdIn(InputStream in) {
        this.in = in;
    }

    public void setStdOut(PrintStream out) {
        this.out = out;
    }

    public Object call() throws Exception {
        out.write(in.read());
        return null;
    }

}

无需进程。任何解决方案(甚至一个使用进程)几乎肯定会以某种方式要求对Callables进行代码更改。这是最简单的(只需用this.out替换System.out)。

答案 1 :(得分:1)

stdin / stdout可以重定向到整个系统,但我不确定它是否可以重定向到单个线程 - 你总是从System获取它。 (你可以让System.out转到另一个流,我已经用它来捕获堆栈跟踪,然后才有一个方法来获取跟踪字符串)

你可以重定向stdin / stdout,运行callable然后重定向它,但是如果在重定向的时候还有其他任何东西使用System.out,那么它也会转到你的新文件。

如果你想走那条路,方法将是System.setIn()和System.setOut()(和System.setErr())。

答案 2 :(得分:1)

努力使用上面的参数化,依赖注入或任何你想要调用的代码来构建代码。避免使用静力学,即使是那些打扮成单身或藏在坏图书馆里的人。

如果您不想删除System.in/out/err的使用情况,那么您很幸运。这些可以使用System.set(In/Out/Err)进行全局设置。为了能够针对各个线程进行不同的流式设置,请设置一个使用ThreadLocal来查找要委派的目标的实现。线程本地通常是邪恶的,但在不幸的情况下可能很有用。

从澄清来看,原始海报似乎无需创建单独的流程。

答案 3 :(得分:0)

看看ProcessBuilder类,它为您提供了捕获它启动的进程的stdout和stderr的选项。

您可以创建一个运行Callable的Main类,然后使用ProcessBuilder将其作为另一个jvm启动。 Main类可以接受您的callable的类名作为命令行输入参数,并使用Class.forName()和Class.newInstance()加载它。

另一种方法是,如果您希望它运行特定的可调用实例,则在启动另一个进程之前将实例序列化为文件(这将是两个进程之间非常粗略的通信形式)。

问题是,你为什么要这样做?你能不能在另一个线程中运行你的callable? java.util.concurrent有一些有用的线程池,仅供参考。