Java:在单独的进程中运行一个Callable
假设实例x
为Callable<T>
,如何在单独的进程中运行x
以便我可以重定向进程的标准输入和输出?例如,有没有办法从Callable
建立Process
?是否有标准的Executor
可以控制输入和输出?Java:在单独的进程中运行一个Callable
[更新]这不是重要的是,Callable
在执行一个新的进程,而不是一个新的线程。我想要的是将Callable
实例放在一个“线束”中,这样我就可以控制它的标准输入/标准输出。 AFAIK,这需要一个新的过程。
更普遍:
给定一个实例x赎回利用全局变量A和B,我怎么能同时运行这样的x即x看到自定义值A和B,而不是“原始”的价值观A和B?
而最好的答案是,不要使用全局变量。依赖注入类似的东西。扩展Callable并添加方法setStdIn,setStdOut(和setStdErr,如果您需要的话)。
我知道这不是您正在寻找的答案,但我所看到的解决方案都需要一个新的过程,并且您将Callable变为新过程的唯一方法是更改代码的Callable,所以它是可序列化的,或者提供一个类名或者其他一些破解,所以不要进行会给你一个讨厌,脆弱的解决方案的修改,而只是做正确的*
*“right”被广泛接受的依赖注入模式提供了松耦合。因人而异
UPDATE:为响应评述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)。
看一看的ProcessBuilder类,它可以让你捕捉到它启动过程的输出和错误的选项。
您可以创建一个运行的可调用一个主类,然后再启动它作为一个的ProcessBuilder其他JVM。 Main类可以接受你的callable的类名作为命令行输入参数,并使用Class.forName()和Class.newInstance()加载它。
如果您希望它运行特定的可调用实例,另一种方法是在启动其他进程(这将是两个进程之间非常粗略的通信形式)之前将该实例序列化为文件。
的问题是,你为什么要这么做?你不能在另一个线程中运行你的可调用吗? java.util.concurrent有一些有用的线程池,仅供参考。
标准输入/标准输出可以重定向整个系统,但我不确定它可以重定向到单个线程 - 你总是从系统中获取它。 (尽管你可以让System.out转到另一个流,但我曾用它来捕获堆栈跟踪,然后才有一种方法将跟踪作为字符串)
您可以重定向stdin/stdout,然后运行可调用重定向它,但是如果其他任何东西在重定向时使用System.out,它也会转到您的新文件。
如果你想去那条路线,方法将是System.setIn()和System.setOut()(和System.setErr())。
尽量使用上面的参数化,依赖注入或任何你想调用它的结构来构造你的代码。避免静态,即使那些打扮成单身或隐藏在不好的图书馆中。
如果您不想删除System.in/out/err
的使用情况,那么您很幸运。这些可以全局设置为System.set(In/Out/Err)
。为了能够为单个线程进行不同的流式传输,请设置一个使用ThreadLocal
来查找要委派的目标的实现。线程本地人通常是邪恶的,但在不幸的情况下可能有用。
从澄清,似乎原来的海报没有必要创建一个单独的过程。
ProcessBuilder,AFAICT需要命令行字符串而不是Callable。我一定要调用这个实例,而不是根据类名创建一个新的实例。至于进程与线程,请参阅上文。 – 2008-12-04 23:43:26
我的意思是说,您将java.exe作为ProcessBUilder的命令,对于Main类,您提供了一个运行可调用的包装器。当然,您需要序列化实例并将文件名作为参数传递给主类。 或者只是使用System.setIn()/ out()等。 – Yoni 2008-12-06 03:45:36