Как правило, когда мы запускаем методы в других классах в Java, независимо от того, являются ли они статическими или динамичными вызовами, они выполняются в текущем процессе, то есть есть только один экземпляр Java Virtual Machine. Иногда нам нужно запустить несколько подпроцессов Java через код Java. Хотя это занимает некоторые системные ресурсы, это сделает программу более стабильной, потому что вновь запущенная программа работает в различных процессах виртуальных машин.
В Java мы можем использовать два метода для достижения этого требования. Самый простой способ - выполнить Java ClassName с помощью метода EXEC во время выполнения. Если выполнение успешно, этот метод возвращает объект процесса. Давайте посмотрим на простой пример ниже.
// test1.java -файл импорт java.io.*; ; System.out.println ("Вызов успешно!");}} // test_exec.javapublic class test_exec {public static void main (string [] args) {runtime run = runtime.ge truntime (); process p = run. exec ("java test1");}}После запуска программы через Java test_exec я обнаружил, что на дисков C был дополнительный файл test1.txt, но в консоли не появилась информация о выводе «успешно!» Следовательно, можно сделать вывод, что тест был успешно выполнен, но по какой -то причине выходная информация о тесте не выводится в консоли test_exec. Эта причина также очень проста, потому что дочерний процесс test_exec создается с помощью EXEC.
Если вы хотите вывести выходную информацию о детском процессе, вы можете получить выходной поток дочернего процесса через процесс GetInputStream (вывод в детском процессе, вход в родительский процесс), а затем перенести выходной поток ребенка Процесс из вывода консоли родительского процесса. Конкретный код реализации выглядит следующим образом:
// test_exec_out.javaimport java.io.*; Public class test_exec_out {public static void main (string [] args) {runtime run = runtime.getruntime (); process p = run.exec ("java test1"); = New BufferedInputStream (p.getInputStream ()); BufferedReader Br = New BufferedReader (New InputStreamReader (in)); String S; while ((s = br.readline ())! = null) System.out.println (s) ;}}
Как видно из приведенного выше кода, в TEST_EXEC_OUT.JAVA выходная информация о дочернем процессе читается по строке, а затем выход выполняется на каждой строке в TEST_EXEC_OUT. Приведенное выше обсуждение - как получить выходную информацию о детском процессе. Затем, в дополнение к выходной информации, есть также входная информация. Поскольку дочерний процесс не имеет собственной консоли, входная информация также должна быть предоставлена родительским процессом. Мы можем предоставить входную информацию в процесс ребенка с помощью метода процесса GetOutputStream (то есть входная информация от родительского процесса в процесс ребенка, а не входную информацию из консоли). Мы можем посмотреть на следующий код:
// test2.java файл импорт java.io.*; «Информация, введенная родительским процессом:" + br.readline ());}} // test_exec_in.javaimport java.io.*; .getRuntime (); Process P = run.exec ("Java test2"); BufferedWriter BW = New BufferedWriter (New OutputStreamWriter (p.getOutputStream ())); BW.Write («Выходная информация о детском процессе»); BW. flush (); bw.close (); Из приведенного выше кода мы видим, что Test1 получает информацию, отправленную TEST_EXEC_IN и выводит ее. Когда вы не добавляете bw.flash () и bw.close (), информация не достигнет дочернего процесса, что означает, что дочерний процесс входит в состояние блокировки, но после выхода родительского процесса, дочерний процесс также выходит Полем Если вы хотите доказать это, вы можете добавить System.in.read () в конце, а затем просмотреть процесс Java через диспетчер задач (под Windows), и вы обнаружите, что если вы добавите bw.flush () и bw .close (), существует только один процесс Java, если они удалены, существуют два процесса Java. Это связано с тем, что, если информация передается на выходы Test2, Test2 после получения информации. Вот одна вещь, которую нужно объяснить, что выполнение EXEC является асинхронным и не перестанет выполнять следующий код, потому что выполняется определенная программа, которая заблокирована. Следовательно, после запуска тестирования2 можно выполнить следующий код.
Метод EXEC был перезагрузен много раз. То, что используется выше, это просто перегрузка этого. Он также может отделять команды и параметры, такие как Exec ("java.test2"), может быть записано как exec ("java", "test2"). Exec также может запускать виртуальные машины Java с различными конфигурациями с помощью указанных переменных среды.
В дополнение к использованию метода EXEC Runtime для создания дочернего процесса, вы также можете построить дочерний процесс через процесс Scuilder. Использование процесса построения следующего:
// test_exec_out.javaimport java.io.*; Public class test_exec_out {public static void main (string [] args) {processbuilder pb = new Processbui lder ("java", "test1"); Process p = pb.start () ;При установлении дочерних процессов процесс -застройка аналогична времени выполнения, используя метод start () для запуска дочернего процесса, в то время как выполнение использует метод EXEC. После получения процесса их операции точно такие же.
Как и во время выполнения, процесс -заработок также может установить информацию о среде, рабочий каталог и т. Д. Выполняемый файл. В следующем примере описывается, как установить эту информацию, используя процесс строителя.
ProcessBuilder pb = new ProcessBuilder ("command", "arg2", "arg2", '' ''); // Установить переменную среду map <string, string> env = pb.environment (); env.put ("key1", ::::::::::::::::: ::::::::::::::::: ::::::::::::::::::::::::::::: :::: "" value1 "); env.remove (" key2 "); env.put (" key2 ", env .get ("key1") + "_test"); pb.directory ("../ ABCD"); Проблема блокировки процесса
Процессы, представленные в процессе, иногда не очень хорошо работают на некоторых платформах, особенно при работе на стандартных входных потоках, выходных потоков и выходов ошибок, представляющих процессы.
Если оператор в приведенном выше примере, который перечитывает информацию из стандартного вывода, изменяется для чтения из потока вывода ошибок:
stdout = new BufferedReader (New InputStreamReader (P.GetErrorStream ()));
Затем программа будет блокировать и не может быть выполнена, но висела там.
Когда процесс запускается, стандартный выходной поток и выходной поток ошибки включаются, чтобы подготовить выход, а когда процесс заканчивается, они закрыты. В приведенном выше примере выходной поток ошибки не имеет данных для вывода, а стандартный выходной поток имеет выходные данные. Поскольку данные в стандартном выходном потоке не считываются, процесс не закончится, а выходной поток ошибки не будет закрыт. Чтобы решить эту проблему, вы можете сначала прочитать стандартный выходной поток, а затем прочитать неправильный выходной поток в соответствии с фактическим порядком выхода.
Однако во многих случаях выходная последовательность не может быть четко известна, особенно когда требуется стандартный ввод, ситуация будет более сложной. В настоящее время потоки могут использоваться для обработки стандартного вывода, вывода ошибок и стандартного ввода отдельно, а поток или данные могут быть прочитаны в соответствии с их бизнес -логикой.
Для проблем, вызванных стандартными выходными потоками и ошибочными выводами, вы можете использовать метод RedireCterrorStream (), чтобы объединить их в один.
При использовании метода Process Waitfor () в программе, особенно при вызове метода waitfor () перед чтением, он также может вызвать блокировку. Вы можете использовать методы потока для решения этой проблемы, или вы можете позвонить в метод Waitfor () после чтения данных, чтобы дождаться завершения программы.
Короче говоря, я ввожу использование класса ProcessBuilder, используя метод RedireCterrorStream для объединения стандартного выходного потока и выходного потока ошибки в один. , а затем вызовите метод waitfor (), чтобы дождаться завершения процесса.
нравиться:
Импорт Java.io.buffered Reader; {try {list <string> list = new Arraylist <string> (); Добавить (cmd.exe »); ); (line = stdout.readline ())! = null) {System.out.println (line); stdou t .close ();