Джава:Запуск вызываемого объекта в отдельном процессе

StackOverflow https://stackoverflow.com/questions/342435

Вопрос

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

[ОБНОВЛЕНИЕ] Не важно, что Callable выполнить в новом процессе, а не в новом потоке.Я хочу поставить Callable экземпляр в «жгуте», чтобы я мог управлять его стандартным вводом/выводом.AFAIK, это требует нового процесса.

Это было полезно?

Решение

В более общем смысле:

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

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

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

* «Правильно» — использовать широко распространенный шаблон внедрения зависимостей для обеспечения слабой связи.ЯММВ

ОБНОВЛЯТЬ:В ответ на комментарий 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;
    }

}

Нет необходимости в процедуре.Любое решение (даже использующее процессы) почти наверняка потребует каким-либо образом внести изменения в код вызываемых объектов.Это самый простой вариант (просто замените System.out на this.out).

Другие советы

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

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

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

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

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

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

Взгляните на класс ProcessBuilder, он дает вам возможность захватить stdout и stderr запускаемого им процесса.

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top