Secara umum, ketika kami menjalankan metode di kelas lain di Java, apakah mereka adalah panggilan statis atau dinamis, mereka dieksekusi dalam proses saat ini, yaitu, hanya ada satu instance mesin virtual Java yang berjalan. Terkadang, kita perlu memulai beberapa subproses Java melalui kode Java. Meskipun melakukan ini mengambil beberapa sumber daya sistem, ini akan membuat program lebih stabil karena program yang baru dimulai berjalan dalam proses mesin virtual yang berbeda.
Di Java kita dapat menggunakan dua metode untuk mencapai persyaratan ini. Cara termudah adalah menjalankan java className melalui metode exec di runtime. Jika eksekusi berhasil, metode ini mengembalikan objek proses. Mari kita lihat contoh sederhana di bawah ini.
// test1.java file impor java.io.*; Tes kelas publik {public static void main (string [] args) {fileoutputStream fout = new fileoutputStream ("c: // test1 .txt"); fout.close () ; System.out.println ("Disebut Berhasil!");}} // test_exec.javapublic kelas test_exec {public static void main (string [] args) {runtime run = runtime.ge truntime (); proses p = run. exec ("java test1");}}Setelah menjalankan program melalui java test_exec, saya menemukan bahwa ada file test1.txt tambahan pada drive C, tetapi informasi output "disebut dengan sukses!" Oleh karena itu, dapat disimpulkan bahwa tes telah dieksekusi dengan sukses, tetapi untuk beberapa alasan, informasi output tes bukan output di konsol test_exec. Alasan ini juga sangat sederhana, karena proses anak test_exec dibuat menggunakan eksekutif.
Jika Anda ingin mengeluarkan informasi output dari proses anak, Anda dapat memperoleh aliran output dari proses anak melalui proses getInputStream dalam proses (output dalam proses anak, input dalam proses induk), dan kemudian transfer aliran output anak Proses dari output konsol proses induk. Kode implementasi spesifik adalah sebagai berikut:
// test_exec_out.javaimport java.io.*; Kelas publik test_exec_out {public static void main (string [] args) {runtime run = runtime.getRuntime (); proses p = run.exec ("java test1"); bufferedInputStream in = baru bufferedInputStream (p.getInputStream ()); bufferedReader br = BufferedReader baru (inputStreamReader baru (IN)); string s; while ((s = br.readline ())! = null) system.out.println (s) ;}}
Seperti yang dapat dilihat dari kode di atas, dalam test_exec_out.java, informasi output dari proses anak dibaca berdasarkan baris, dan kemudian output dilakukan pada setiap baris di test_exec_out. Diskusi di atas adalah cara mendapatkan informasi output dari proses anak. Kemudian, selain informasi output, ada juga informasi input. Karena proses anak tidak memiliki konsol sendiri, informasi input juga harus disediakan oleh proses induk. Kami dapat memberikan informasi input ke proses anak melalui metode proses getOutputStream (yaitu, informasi input dari proses induk ke proses anak, daripada memasukkan informasi dari konsol). Kita dapat melihat kode berikut:
// test2.java file impor java.io.*; Tes kelas publik {public static void main (string [] args) {bufferedReader br = new buferedReader (inputStreamRead ER (System.in)); System.out.println (System.println ( "Informasi yang dimasukkan oleh proses induk:" + br.readline ());}} // test_exec_in.javaimport java.io.*; Kelas publik test_exec_in {public static void main (string [] args) {run time run = runtime) .getRuntime (); proses p = run.exec ("java test2"); bufferedwriter bw = baru buferedwriter (outputStreamWriter baru (p.getoutputStream ())); bw.write ("output ke informasi proses anak"); bw. flush (); bw.close (); Dari kode di atas, kita dapat melihat bahwa test1 mendapatkan informasi yang dikirim oleh test_exec_in dan mengeluarkannya. Ketika Anda tidak menambahkan bw.flash () dan bw.close (), informasi tidak akan mencapai proses anak, yang berarti bahwa proses anak memasuki keadaan pemblokiran, tetapi karena proses induk telah keluar, proses anak juga keluar . Jika Anda ingin membuktikan ini, Anda dapat menambahkan System.in.read () di akhir dan kemudian melihat proses Java melalui Task Manager (di bawah Windows), dan Anda akan menemukan bahwa jika Anda menambahkan bw.flush () dan BW .close (), hanya satu proses Java, jika mereka dihapus, ada dua proses Java. Ini karena, jika informasi diteruskan ke test2, test2 keluar setelah mendapatkan informasi. Berikut adalah satu hal yang harus dijelaskan bahwa eksekusi EXEC tidak sinkron dan tidak akan berhenti menjalankan kode berikut karena program tertentu yang dieksekusi diblokir. Oleh karena itu, setelah menjalankan test2, kode berikut masih dapat dieksekusi.
Metode EXEC telah dimuat ulang berkali -kali. Apa yang digunakan di atas hanyalah kelebihan bebannya. Ini juga dapat memisahkan perintah dan parameter, seperti exec ("java.test2") dapat ditulis sebagai exec ("java", "test2"). EXEC juga dapat menjalankan mesin virtual Java dengan konfigurasi yang berbeda melalui variabel lingkungan yang ditentukan.
Selain menggunakan metode EXEC Runtime untuk membangun proses anak, Anda juga dapat membangun proses anak melalui proses proses. Penggunaan ProcessBuilder adalah sebagai berikut:
// test_exec_out.javaimport java.io.*; Kelas publik test_exec_out {public static void main (string [] args) {ProcessBuilder pb = ProcessBui lder ("java", "test1"); Process p = pb.start () ;……}}Dalam membangun proses anak, ProcessBuilder mirip dengan runtime. Setelah mendapatkan prosesnya, operasinya persis sama.
Seperti runtime, ProcessBuilder juga dapat mengatur informasi lingkungan, direktori kerja, dll. Dari file yang dapat dieksekusi. Contoh berikut menjelaskan cara mengatur informasi ini menggunakan ProcessBuilder.
ProcessBuilder pb = new ProcessBuilder ("command", "arg2", "arg2", '' '); // atur peta variabel lingkungan <string, string> env = pb.environment (); env.put ("key1", ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::: "value1")); env.remove ("key2"); env.put ("key2", env .get ("key1") + "_test"); pb.directory ("../ abcd"); Masalah pemblokiran proses
Proses yang diwakili oleh proses terkadang tidak bekerja dengan baik pada beberapa platform, terutama ketika beroperasi pada aliran input standar, aliran output dan output kesalahan yang mewakili proses.
Jika pernyataan dalam contoh di atas yang membaca ulang informasi dari output standar dimodifikasi untuk dibaca dari aliran output kesalahan:
stdout = BufferedReader baru (inputStreamReader baru (p.getErrorStream ()));
Kemudian program akan memblokir dan tidak dapat dieksekusi, tetapi hang di sana.
Ketika proses dimulai, aliran output standar dan aliran output kesalahan dihidupkan untuk menyiapkan output, dan ketika proses berakhir, mereka ditutup. Dalam contoh di atas, aliran output kesalahan tidak memiliki data untuk menjadi output, dan aliran output standar memiliki output data. Karena data dalam aliran output standar tidak dibaca, prosesnya tidak akan berakhir dan aliran output kesalahan tidak akan ditutup. Untuk mengatasi masalah ini, Anda dapat membaca aliran output standar pertama dan kemudian membaca aliran output yang salah sesuai dengan urutan aktual output.
Namun, dalam banyak kasus, urutan output tidak dapat diketahui dengan jelas, terutama ketika input standar diperlukan, situasinya akan lebih rumit. Pada saat ini, utas dapat digunakan untuk memproses output standar, output kesalahan dan input standar secara terpisah, dan aliran atau data dapat dibaca sesuai dengan hubungan logika bisnis mereka.
Untuk masalah yang disebabkan oleh aliran output standar dan aliran output yang keliru, Anda dapat menggunakan metode RedirecterrorStream () ProcessBuilder untuk menggabungkannya menjadi satu.
Saat menggunakan metode Process's WaitFor () dalam suatu program, terutama saat memanggil metode WaitFor () sebelum membaca, itu juga dapat menyebabkan penyumbatan. Anda dapat menggunakan metode utas untuk menyelesaikan masalah ini, atau Anda dapat menelepon metode WaitFor () setelah membaca data untuk menunggu program berakhir.
Singkatnya, di sini saya memperkenalkan penggunaan kelas ProcessBuilder, menggunakan metode RedirecterrorStream untuk menggabungkan aliran output standar dan aliran output kesalahan menjadi satu. , dan kemudian hubungi metode waitfor () untuk menunggu proses berakhir.
menyukai:
Impor Java.IO.BufferedReader; {coba {Daftar <string> = ArrayList baru <string> (); add (cmd.exe "); ; (line = stdout.readline ())! = null) {System.out.println (line); stdou t .close ();