Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/375.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java:在单独的进程中运行可调用的_Java_Multithreading_Process_Stdout_Stdin - Fatal编程技术网

Java:在单独的进程中运行可调用的

Java:在单独的进程中运行可调用的,java,multithreading,process,stdout,stdin,Java,Multithreading,Process,Stdout,Stdin,给定Callable的x实例,如何在单独的进程中运行x,以便重定向进程的标准输入和输出?例如,是否有一种方法可以从可调用的构建进程?是否有标准的执行器来控制输入和输出 [更新]与新线程相反,Callable在新进程中执行并不重要。我想要的是将可调用的实例放在一个“线束”中,这样我就可以控制它的stdin/stdout。好的,这需要一个新的进程。看看ProcessBuilder类,它为您提供了捕获它启动的进程的stdout和stderr的选项 您可以创建一个运行可调用的主类,然后使用Process

给定
Callable
x
实例,如何在单独的进程中运行
x
,以便重定向进程的标准输入和输出?例如,是否有一种方法可以从
可调用的
构建
进程
?是否有标准的
执行器
来控制输入和输出


[更新]与新线程相反,
Callable
在新进程中执行并不重要。我想要的是将
可调用的
实例放在一个“线束”中,这样我就可以控制它的stdin/stdout。好的,这需要一个新的进程。

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

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

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

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

更一般地说:

给定一个利用全局变量A和B可调用的实例x,如何并发运行x,使x看到A和B的自定义值,而不是A和B的“原始”值

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

我知道这不是你想要的答案,但是我看到的解决方案都需要一个新的进程,而你将可调用的代码转换成一个新进程的唯一方法是更改可调用的代码,使其可序列化,或者提供一个类名,或者其他一些破解方法,所以不要做出会给你带来麻烦的更改,脆性解决方案,只要做对就行*

*“正确”是使用广泛接受的依赖注入模式来提供松耦合。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;
导入java.io.PrintStream;
导入java.util.concurrent.Callable;
公共接口MyCallable扩展了Callable{
无效设置TDIN(输入流输入);
无效设置输出(打印流输出);
}
您的任务如下所示:

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;
    }
import java.io.InputStream;
导入java.io.PrintStream;
公共类CallableTask实现MyCallable{
私有InputStream in=System.in;
私有打印流输出=System.out;
公共无效设置TDIN(输入流输入){
this.in=in;
}
公共无效设置输出(打印流输出){
this.out=out;
}
公共对象调用()引发异常{
out.write(in.read());
返回null;
}
}


不需要一个过程。任何解决方案(即使是使用进程的解决方案)都几乎肯定需要以某种方式对可调用项进行代码更改。这是最简单的(只需将System.out替换为This.out)。

/stdin/stdout可以重定向到整个系统,但我不确定它是否可以重定向到单个线程——您总是从系统中获取它。(您可以让System.out转到另一个流,在有方法将跟踪获取为字符串之前,我已经使用它来捕获堆栈跟踪)

您可以重定向stdin/stdout,运行可调用文件,然后将其重定向回,但如果在重定向过程中有任何其他内容使用System.out,它也会转到新文件


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

努力使用上面的参数化、依赖项注入或任何你想调用的方法来构造代码。避免静态,即使是那些装扮成单身或隐藏在坏库中的静态

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


从澄清中可以看出,原始海报似乎不需要创建单独的流程。

ProcessBuilder,AFAICT,想要一个命令行字符串,而不是一个可调用的字符串。我肯定希望调用实例,而不是基于类名创建新实例。至于进程与线程,请参见上文。我的意思是,您将java.exe作为命令提供给ProcessBUilder,对于主类,您将提供一个运行可调用函数的包装器。当然,您需要序列化实例并将文件名作为参数传递给主类。或者只使用System.setIn()/out()等。如果不先回答这个问题,我将如何实现您的建议?“依赖项注入”并不是一个神奇的精灵,它不会让整个问题消失,你知道。这不是魔法,但全局变量被公认为是一种代码气味。依赖注入是一个很好的选择。如果我真的需要一个额外的进程,因为我必须使用的库或多或少依赖于一个全局单例,该怎么办?@Florian你需要问自己几个问题:1)我是否在规避库的意图?如果是,您可能会遇到其他问题,并且在升级库时您的解决方案可能会中断。2) 这个图书馆是个不错的选择吗?我可以使用没有全局依赖关系的其他东西吗?3) 还有别的办法吗?如果在此之后仍然需要新流程,请查看ProcessBuilder。