2008-12-04 6 views
1

В случае экземпляра x из Callable<T>, как я могу запустить x в отдельном процессе, чтобы я мог перенаправить стандартный ввод и вывод процесса? Например, есть ли способ построить Process от Callable? Есть ли стандарт Executor, который дает управление входами и выходами?Java: Запуск вызываемого в отдельном процессе

[UPDATE] Не важно, чтобы Callable выполнялся в новом процессе, а не в новом потоке. Я хочу поставить экземпляр Callable в «упряжь», чтобы я мог контролировать его stdin/stdout. AFAIK, это требует нового процесса.

ответ

2

Более общо:

Учитывая экземпляр х Callable использования глобальных переменных A и B, как я могу запустить х одновременно такие, что х видит собственные значения А и В, а не «оригинальных» значений A и B?

И лучший ответ: не используйте глобальные переменные. Зависимость вводит такие вещи. Расширьте Callable и добавьте методы setStdIn, setStdOut (и setStdErr, если вам это нужно).

Я знаю, что это не тот ответ, который вы ищете, но решения, которые я видел для этого, требуют нового процесса, и единственный способ, которым вы получаете этот Callable в новый процесс, - это изменить код Callable, так что он сериализуется или предоставляет имя класса или какой-либо другой хак, поэтому вместо внесения изменений, которые дадут вам неприятное, хрупкое решение, просто сделайте это правильно *

* «Право» использовать широко распространенная схема инъекции зависимостей для обеспечения рыхлой связи. YMMV

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 в некотором роде. Это самый простой (просто замените System.out на this.out).

0

Посмотрите на класс ProcessBuilder, он дает вам возможность записывать stdout и stderr процесса, который он запускает.

Вы можете создать Основной класс, который запускает Callable, а затем запустить его как другой jvm с ProcessBuilder. Основной класс может принять имя класса вызываемого в качестве входного параметра командной строки и загрузить его с помощью Class.forName() и Class.newInstance().

Альтернативой, если вы хотите запустить конкретный вызываемый экземпляр, является сериализация экземпляра в файл перед запуском другого процесса (что было бы очень грубой формой связи между двумя процессами).

Вопрос в том, почему вы хотите это сделать? Вы не можете просто запустить свой вызов в другом потоке? java.util.concurrent имеет несколько полезных пулов потоков, только для этого.

+0

ProcessBuilder, AFAICT, хочет строку командной строки, а не вызываемую. Я определенно хочу вызвать экземпляр и не создавать новый экземпляр на основе имени класса. Что касается процесса vs. thread, см. Выше. – 2008-12-04 23:43:26

+0

Я имел в виду, что вы даете java.exe как команду ProcessBUilder, а для основного класса вы даете оболочку, которая запускает вызываемый. Конечно, вам нужно будет сериализовать экземпляр и передать имя файла в качестве параметра в ваш основной класс. Или просто используйте System.setIn()/out() и т. Д. – Yoni 2008-12-06 03:45:36

1

stdin/stdout можно перенаправить для всей системы, но я не уверен, что он может быть перенаправлен для одного потока - вы всегда просто получаете его из системы. (Вы можете заставить System.out перейти к другому потоку, хотя я использовал это, чтобы поймать трассировки стека, прежде чем появился способ получения трассировки в виде строки).

Вы можете перенаправить stdin/stdout, запустить вызываемый, затем перенаправить его обратно, но если что-то еще использует System.out, пока оно перенаправлено, это также перейдет в ваш новый файл.

Методами были бы System.setIn() и System.setOut() (и System.setErr()), если вы хотите пройти этот маршрут.

1

Стремитесь структурировать свой код с помощью Параметризации сверху, зависимостей, или того, что вы хотите назвать. Избегайте статики, даже тех, которые одеты как синглеты или скрыты в плохой библиотеке.

Если вы не хотите удалять использование System.in/out/err, вам повезло. Они могут быть установлены глобально с помощью System.set(In/Out/Err). Чтобы иметь возможность потока по-разному для отдельных потоков, установите реализацию, которая использует ThreadLocal, чтобы найти цель для делегирования. Местные жители, как правило, злые, но могут быть полезны в неудачных ситуациях.

Из пояснений выясняется, что оригинальному плакату не нужно создавать отдельный процесс.