给定一个实例x
,Callable<T>
如何x
在单独的进程中运行,以便可以重定向进程的标准输入和输出?例如,有没有办法Process
从 a 构建 a Callable
?是否有Executor
控制输入和输出的标准?
Callable
[更新]在新进程中执行而不是在新线程中执行并不重要。我想要的是把Callable
实例放在“线束”中,这样我就可以控制它的标准输入/标准输出。AFAIK,这需要一个新的过程。
给定一个实例x
,Callable<T>
如何x
在单独的进程中运行,以便可以重定向进程的标准输入和输出?例如,有没有办法Process
从 a 构建 a Callable
?是否有Executor
控制输入和输出的标准?
Callable
[更新]在新进程中执行而不是在新线程中执行并不重要。我想要的是把Callable
实例放在“线束”中,这样我就可以控制它的标准输入/标准输出。AFAIK,这需要一个新的过程。
更普遍:
给定一个使用全局变量 A 和 B 的 Callable 实例 x,我如何同时运行 x 以使 x 看到 A 和 B 的自定义值,而不是 A 和 B 的“原始”值?
最好的答案是,不要使用全局变量。依赖注入之类的东西。扩展 Callable 并添加方法 setStdIn、setStdOut(如果需要,还可以添加 setStdErr)。
我知道这不是您要寻找的答案,但是我为此看到的解决方案都需要一个新流程,而将 Callable 放入新流程的唯一方法是更改 Callable 的代码它是可序列化的,或提供类名或其他一些技巧,因此不要进行会给您带来讨厌的、脆弱的解决方案的更改,只要做对*
* “正确”是使用广泛接受的依赖注入模式来提供松散耦合。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 进行代码更改。这是最简单的(只需将 System.out 替换为 this.out)。
stdin/stdout 可以重定向到整个系统,但我不确定它是否可以重定向到单个线程——你总是只是从 System. (不过,您可以让 System.out 转到另一个流,在有一种方法可以将跟踪作为字符串获取之前,我已经使用它来捕获堆栈跟踪)
您可以重定向标准输入/标准输出,运行可调用然后将其重定向回来,但如果其他任何东西在重定向时使用 System.out,那也将转到您的新文件。
如果您想走那条路线,方法将是 System.setIn() 和 System.setOut()(和 System.setErr())。
努力使用上面的参数化、依赖注入或任何你想调用的方法来构造你的代码。避免静态,即使是那些装扮成单身人士或隐藏在糟糕图书馆中的人。
如果您不想删除对您的使用,System.in/out/err
那么您很幸运。这些可以用 全局设置System.set(In/Out/Err)
。为了能够为各个线程进行不同的流式传输,请设置一个ThreadLocal
用于查找要委托的目标的实现。线程局部变量通常是邪恶的,但在不幸的情况下可能很有用。
从澄清来看,原始发布者似乎不需要创建单独的过程。
看一下 ProcessBuilder 类,它为您提供了捕获它启动的进程的标准输出和标准错误的选项。
您可以创建一个运行 Callable 的 Main 类,然后将其作为另一个带有 ProcessBuilder 的 jvm 启动。Main 类可以接受您的可调用对象的类名作为命令行输入参数,并使用 Class.forName() 和 Class.newInstance() 加载它。
如果您希望它运行特定的可调用实例,另一种方法是在启动另一个进程之前将实例序列化为文件(这将是两个进程之间通信的一种非常粗略的形式)。
问题是,你为什么要这样做?你不能在另一个线程中运行你的可调用对象吗?java.util.concurrent 有一些有用的线程池,仅此而已。