假設實例x
爲Callable<T>
,如何在單獨的進程中運行x
以便我可以重定向進程的標準輸入和輸出?例如,有沒有辦法從Callable
建立Process
?是否有標準的Executor
可以控制輸入和輸出?Java:在單獨的進程中運行一個Callable
[更新]這不是重要的是,Callable
在執行一個新的進程,而不是一個新的線程。我想要的是將Callable
實例放在一個「線束」中,這樣我就可以控制它的標準輸入/標準輸出。 AFAIK,這需要一個新的過程。
假設實例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