1. การสร้างกระบวนการ Java
Java มีสองวิธีในการเริ่มต้นกระบวนการหรือโปรแกรมอื่น ๆ :
(1) ใช้วิธี EXEC () ของ Runtime (2) ใช้วิธีการเริ่มต้น () ของ ProcessBuilder (2) (2)
1.1 ProcessBuilder
คลาส ProcessBuilder เป็นคลาสใหม่ที่เพิ่มเข้ามาใหม่ใน Java.lang โดย J2SE 1.5 ก่อน J2SE 1.5 การควบคุมกระบวนการและการจัดการถูกนำไปใช้โดยคลาสกระบวนการ
อินสแตนซ์ของ ProcessBuilder แต่ละชุดจะจัดการชุดคุณสมบัติของกระบวนการ วิธีการเริ่มต้น () ใช้คุณสมบัติเหล่านี้เพื่อสร้างอินสแตนซ์กระบวนการใหม่ วิธีการเริ่มต้น () สามารถเรียกได้ซ้ำ ๆ จากอินสแตนซ์เดียวกันเพื่อสร้างกระบวนการเด็กใหม่ที่มีคุณสมบัติเดียวกันหรือที่เกี่ยวข้อง
เครื่องกำเนิดกระบวนการแต่ละกระบวนการจัดการคุณสมบัติกระบวนการเหล่านี้:
คำสั่งคือรายการสตริงที่แสดงไฟล์โปรแกรมภายนอกที่จะเรียกและพารามิเตอร์ (ถ้ามี) ที่นี่รายการสตริงที่เป็นตัวแทนของคำสั่งระบบปฏิบัติการที่ถูกต้องนั้นขึ้นอยู่กับระบบ ตัวอย่างเช่นตัวแปรโดยรวมทุกตัวมักจะกลายเป็นองค์ประกอบในรายการนี้ แต่มีระบบปฏิบัติการที่ต้องการให้โปรแกรมทำเครื่องหมายสายบรรทัดคำสั่งของตัวเอง - ในระบบดังกล่าวการใช้งาน Java อาจต้องใช้คำสั่งเพื่อรวมองค์ประกอบทั้งสองนี้
สภาพแวดล้อมคือการแมปขึ้นอยู่กับระบบจากตัวแปรถึงค่า ค่าเริ่มต้นคือสำเนาของสภาพแวดล้อมกระบวนการปัจจุบัน (ดู System.getenv ())
ไดเรกทอรีการทำงาน ค่าเริ่มต้นคือไดเรกทอรีการทำงานปัจจุบันของกระบวนการปัจจุบันซึ่งมักจะตั้งชื่อตามคุณสมบัติของระบบ user.dir
คุณสมบัติ RedirecterRorStream ในขั้นต้นคุณสมบัตินี้เป็นเท็จซึ่งหมายความว่าเอาต์พุตมาตรฐานและเอาต์พุตข้อผิดพลาดของกระบวนการเด็กจะถูกส่งไปยังสตรีมอิสระสองสายที่สามารถเข้าถึงได้ผ่านวิธีการ process.getInputStream () และ process.getErrorStream () หากค่าถูกตั้งค่าเป็นจริงข้อผิดพลาดมาตรฐานจะถูกรวมเข้ากับเอาต์พุตมาตรฐาน สิ่งนี้ทำให้ง่ายต่อการเชื่อมโยงข้อความแสดงข้อผิดพลาดและเอาต์พุตที่สอดคล้องกัน ในกรณีนี้ข้อมูลที่ผสานสามารถอ่านได้จากสตรีมที่ส่งคืนโดย process.getInputStream () ในขณะที่สตรีมอ่านจาก process.getErrorStream () จะถึงจุดสิ้นสุดของไฟล์โดยตรง
การแก้ไขคุณสมบัติของตัวสร้างกระบวนการจะส่งผลกระทบต่อกระบวนการที่ตามมาเริ่มต้นโดยวิธีการเริ่มต้น () ของวัตถุ แต่จะไม่ส่งผลกระทบต่อกระบวนการที่เริ่มต้นก่อนหน้านี้หรือ Java เอง การตรวจสอบข้อผิดพลาดส่วนใหญ่ดำเนินการโดยวิธีการเริ่มต้น () สถานะของวัตถุสามารถแก้ไขได้ แต่ start () จะล้มเหลวด้วยวิธีนี้ ตัวอย่างเช่นการตั้งค่าคุณสมบัติคำสั่งเป็นรายการว่างจะไม่โยนข้อยกเว้นเว้นแต่จะเริ่มต้น () รวมอยู่ด้วย
โปรดทราบว่าคลาสนี้ไม่ได้ซิงโครนัส หากหลายเธรดเข้าถึง ProcessBuilder ในเวลาเดียวกันและอย่างน้อยหนึ่งเธรดหนึ่งโครงสร้างจะปรับเปลี่ยนคุณสมบัติหนึ่งในคุณสมบัติหนึ่งมันจะต้องรักษาการซิงโครไนซ์ภายนอก
สรุปวิธีการก่อสร้าง
ProcessBuilder (รายการ <string> คำสั่ง)
สร้างตัวสร้างกระบวนการโดยใช้โปรแกรมระบบปฏิบัติการและพารามิเตอร์ที่ระบุ
ProcessBuilder (สตริง ... คำสั่ง)
สร้างตัวสร้างกระบวนการโดยใช้โปรแกรมระบบปฏิบัติการและพารามิเตอร์ที่ระบุ
สรุปวิธีการ
รายการ <String> คำสั่ง ()
ส่งคืนโปรแกรมระบบปฏิบัติการและพารามิเตอร์ของเครื่องกำเนิดกระบวนการนี้
คำสั่ง processBuilder (รายการ <string> คำสั่ง)
ตั้งค่าโปรแกรมระบบปฏิบัติการและพารามิเตอร์ของเครื่องกำเนิดกระบวนการนี้
คำสั่ง processbuilder (สตริง ... คำสั่ง)
ตั้งค่าโปรแกรมระบบปฏิบัติการและพารามิเตอร์ของเครื่องกำเนิดกระบวนการนี้
ไดเรกทอรีไฟล์ ()
ส่งคืนไดเรกทอรีการทำงานของเครื่องกำเนิดกระบวนการนี้
ไดเรกทอรี ProcessBuilder (ไดเรกทอรีไฟล์)
ตั้งค่าไดเรกทอรีการทำงานสำหรับเครื่องกำเนิดกระบวนการนี้
แผนที่ <สตริงสตริง> สภาพแวดล้อม ()
ส่งคืนมุมมองการแมปสตริงของสภาพแวดล้อมตัวสร้างกระบวนการนี้
บูลีน redirecterRorStream ()
แจ้งเครื่องกำเนิดกระบวนการว่าจะรวมข้อผิดพลาดมาตรฐานและเอาต์พุตมาตรฐานหรือไม่
ProcessBuilder redirecterRorStream (บูลีน redirecterRorStream)
ตั้งค่าคุณสมบัติ RedireCterRorStream ของเครื่องกำเนิดกระบวนการนี้
เริ่มกระบวนการ ()
เริ่มกระบวนการใหม่โดยใช้คุณสมบัติของเครื่องกำเนิดกระบวนการนี้
1.2 รันไทม์
แอปพลิเคชัน Java แต่ละตัวมีอินสแตนซ์ของคลาสรันไทม์ทำให้แอปพลิเคชันเชื่อมต่อกับสภาพแวดล้อมที่ทำงาน可以通过getRuntime 方法获取当前运行时。
แอปพลิเคชันไม่สามารถสร้างอินสแตนซ์คลาสรันไทม์ของตนเองได้ อย่างไรก็ตามคุณสามารถใช้วิธี getRuntime เพื่อรับการอ้างอิงไปยังวัตถุรันไทม์รันไทม์ปัจจุบัน เมื่อคุณได้รับการอ้างอิงไปยังวัตถุรันไทม์ปัจจุบันคุณสามารถเรียกใช้วิธีวัตถุรันไทม์เพื่อควบคุมสถานะและพฤติกรรมของเครื่องเสมือน Java
รหัสรวบรวมรหัส Java
เป็นโมฆะ addshutdownhook (เธรดเบ็ด)
ลงทะเบียนเครื่องเสมือนใหม่เพื่อปิดเบ็ด
INT araikeprocessors ()
ส่งคืนจำนวนโปรเซสเซอร์ที่มีอยู่ไปยังเครื่องเสมือน Java
กระบวนการ EXEC (คำสั่งสตริง)
เรียกใช้คำสั่งสตริงที่ระบุในกระบวนการแยกต่างหาก
กระบวนการ EXEC (String [] CMDARRAY)
ดำเนินการคำสั่งและตัวแปรที่ระบุในกระบวนการแยกต่างหาก
กระบวนการ exec (string [] cmdarray, string [] envp)
ดำเนินการคำสั่งและตัวแปรที่ระบุในกระบวนการแยกต่างหากของสภาพแวดล้อมที่ระบุ
กระบวนการ exec (string [] cmdarray, string [] envp, ไฟล์ dir)
ดำเนินการคำสั่งและตัวแปรที่ระบุในกระบวนการแยกต่างหากในสภาพแวดล้อมที่ระบุและไดเรกทอรีการทำงาน
กระบวนการ EXEC (คำสั่งสตริง, สตริง [] envP)
เรียกใช้คำสั่งสตริงที่ระบุในกระบวนการแยกต่างหากของสภาพแวดล้อมที่ระบุ
กระบวนการ EXEC (คำสั่งสตริง, สตริง [] envP, ไฟล์ dir)
เรียกใช้คำสั่งสตริงที่ระบุในกระบวนการแยกต่างหากด้วยสภาพแวดล้อมที่ระบุและไดเรกทอรีการทำงาน
เป็นโมฆะออก (สถานะ int)
ยุติเครื่องเสมือน Java ที่กำลังทำงานอยู่ในปัจจุบันโดยเริ่มต้นลำดับการปิดเครื่องของเครื่องเสมือน
Freememory ยาว ()
ส่งคืนจำนวนหน่วยความจำฟรีในเครื่องเสมือน Java
เป็นโมฆะ GC ()
เรียกใช้นักสะสมขยะ
InputStream getLocalizedInputStream (inputStream in)
ล้าสมัย. เริ่มต้นด้วย JDK 1.1 วิธีที่ต้องการสำหรับการแปลงสตรีมไบต์ที่เข้ารหัสในเครื่องเป็นสตรีมอักขระ Unicode คือการใช้คลาส InputStreamReader และ BufferedReader
OutputStream getLocalizedOutputStream (OutputStream ออก)
ล้าสมัย. เริ่มต้นด้วย JDK 1.1 วิธีที่ต้องการสำหรับการแปลงสตรีมอักขระ Unicode เป็นสตรีมไบต์ที่เข้ารหัสในเครื่องคือการใช้ UputStreamWriter, BufferedWriter และคลาส Printwriter
รันไทม์คงที่ getRuntime ()
ส่งคืนวัตถุรันไทม์ที่เกี่ยวข้องกับแอปพลิเคชัน Java ปัจจุบัน
void halt(int status)
บังคับให้ยุติเครื่องเสมือน Java ที่กำลังทำงานอยู่ในปัจจุบัน
เป็นโมฆะโหลด (ชื่อไฟล์สตริง)
โหลดชื่อไฟล์ที่ระบุเป็นไลบรารีแบบไดนามิก
เป็นโมฆะ LoadLibrary (String libname)
โหลดไลบรารีแบบไดนามิกพร้อมชื่อไลบรารีที่ระบุ
ยาว maxmemory ()
ส่งคืนจำนวนหน่วยความจำสูงสุด Java Virtual Machine พยายามใช้
บูลีน removeshutdownhook (hook thread)
ยกเลิกการลงทะเบียนเครื่องเสมือนที่ลงทะเบียนก่อนหน้านี้เพื่อปิดเบ็ด
เป็นโมฆะ runfinalization ()
เรียกใช้วิธีการสิ้นสุดของวัตถุทั้งหมดที่ระงับการสรุป
โมฆะคงที่ runfinalizersonexit (ค่าบูลีน)
ล้าสมัย. วิธีนี้เองไม่ปลอดภัย มันอาจเรียกวิธีการสุดท้ายเกี่ยวกับวัตถุที่ใช้ในขณะที่เธรดอื่น ๆ กำลังทำงานกับวัตถุเหล่านั้นส่งผลให้เกิดพฤติกรรมที่ไม่ถูกต้องหรือหยุดชะงัก
TotalMemory ยาว ()
ส่งคืนจำนวนหน่วยความจำทั้งหมดในเครื่องเสมือน Java
เป็นโมฆะ traceinstructions (บูลีนออน)
เปิด/ปิดการติดตามคำสั่ง
เป็นโมฆะ tracemethodcalls (บูลีน)
เปิดใช้งาน/ปิดใช้งานวิธีการติดตามการโทร
1.3 กระบวนการ
ไม่ว่าวิธีใดที่ใช้ในการเริ่มต้นกระบวนการอินสแตนซ์ของคลาสกระบวนการแสดงถึงกระบวนการเริ่มต้นจะถูกส่งคืนซึ่งสามารถใช้ในการควบคุมกระบวนการและรับข้อมูลที่เกี่ยวข้อง คลาสกระบวนการให้วิธีการดำเนินการจากอินพุตกระบวนการเอาต์พุตการดำเนินการไปยังกระบวนการรอเสร็จสิ้นกระบวนการตรวจสอบสถานะการออกของกระบวนการและทำลาย (ฆ่า) กระบวนการ:
เป็นโมฆะทำลาย ()
ฆ่ากระบวนการเด็ก
โดยทั่วไปวิธีนี้วิธีนี้ไม่สามารถฆ่ากระบวนการที่เริ่มต้นได้ดังนั้นจึงเป็นการดีกว่าที่จะไม่ใช้
int exitvalue ()
ส่งคืนค่าออกของกระบวนการเด็ก
เมธอด exitValue () จะมีค่าผลตอบแทนปกติเฉพาะหลังจากกระบวนการเริ่มต้นเสร็จสิ้นการดำเนินการหรือออกเนื่องจากข้อยกเว้นมิฉะนั้นจะมีข้อยกเว้นจะถูกโยนลงไป
InputStream GeterRorStream ()
รับกระแสความผิดพลาดของกระบวนการเด็ก
หากเอาต์พุตข้อผิดพลาดถูกเปลี่ยนเส้นทางเอาต์พุตข้อผิดพลาดจะไม่สามารถอ่านได้จากสตรีม
InputStream getInputStream ()
รับกระแสอินพุตของกระบวนการเด็ก
เอาต์พุตมาตรฐานของกระบวนการสามารถอ่านได้จากสตรีมนี้
OutputStream getOutputStream ()
รับกระแสเอาต์พุตของกระบวนการเด็ก
ข้อมูลที่เขียนไปยังสตรีมใช้เป็นอินพุตมาตรฐานไปยังกระบวนการ
int waitfor ()
ทำให้เธรดปัจจุบันรอหากจำเป็นจนกว่ากระบวนการที่แสดงโดยวัตถุกระบวนการสิ้นสุดลง
2. ตัวอย่างการเขียนโปรแกรมหลายกระบวนการ
โดยทั่วไปเมื่อเราเรียกใช้วิธีการในคลาสอื่น ๆ ใน Java ไม่ว่าจะเป็นการโทรแบบคงที่หรือแบบไดนามิกพวกเขาจะถูกดำเนินการในกระบวนการปัจจุบันนั่นคือมีอินสแตนซ์ของเครื่องเสมือน Java เพียงตัวเดียวเท่านั้น บางครั้งเราต้องเริ่มต้นกระบวนการย่อย Java หลายรายการผ่านรหัส Java แม้ว่าการทำเช่นนี้จะใช้ทรัพยากรระบบบางอย่าง แต่จะทำให้โปรแกรมมีความเสถียรมากขึ้นเนื่องจากโปรแกรมที่เริ่มต้นใหม่ทำงานในกระบวนการเสมือนจริงที่แตกต่างกัน
ใน Java เราสามารถใช้สองวิธีเพื่อให้บรรลุข้อกำหนดนี้ วิธีที่ง่ายที่สุดคือการเรียกใช้ Java classname ผ่านวิธี EXEC ในรันไทม์ หากการดำเนินการสำเร็จวิธีนี้จะส่งคืนวัตถุกระบวนการ ลองมาดูตัวอย่างง่ายๆด้านล่าง
// test1.java นำเข้า Java.io.*; การทดสอบคลาสสาธารณะ {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {fileOutputStream fout = ใหม่ fileOutputStream ("C: // test1 .txt"); ; EXEC ("Java Test1");หลังจากเรียกใช้โปรแกรมผ่าน java test_exec ฉันพบว่ามีไฟล์ test1.txt เพิ่มเติมบนไดรฟ์ C แต่ข้อมูลผลลัพธ์ "เรียกว่าสำเร็จ!" ไม่ปรากฏในคอนโซล ดังนั้นจึงสามารถสรุปได้ว่าการทดสอบได้ดำเนินการสำเร็จแล้ว แต่ด้วยเหตุผลบางอย่างข้อมูลเอาต์พุตของการทดสอบไม่ได้ส่งออกในคอนโซลของ test_exec เหตุผลนี้ก็ง่ายมากเนื่องจากกระบวนการเด็กของ test_exec ถูกสร้างขึ้นโดยใช้ EXEC
หากคุณต้องการเอาต์พุตข้อมูลเอาต์พุตของกระบวนการเด็กคุณสามารถรับกระแสเอาต์พุตของกระบวนการเด็กผ่าน GetInputStream ในกระบวนการ (เอาต์พุตในกระบวนการเด็กอินพุตในกระบวนการหลัก) จากนั้นถ่ายโอนกระแสเอาต์พุตของเด็ก กระบวนการจากเอาต์พุตคอนโซลของกระบวนการหลัก รหัสการใช้งานเฉพาะมีดังนี้:
// test_exec_out.javaimport java.io.*; คลาสสาธารณะ test_exec_out {โมฆะสาธารณะคงที่ (สตริง [] args) {runtime run = runtime.getruntime () = New BufferedInputStream (P.GetInputStream ()); ;ดังที่เห็นได้จากรหัสข้างต้นใน test_exec_out.java ข้อมูลเอาต์พุตของกระบวนการเด็กจะถูกอ่านตามแถวจากนั้นเอาต์พุตจะดำเนินการในแต่ละบรรทัดใน test_exec_out การสนทนาข้างต้นคือวิธีรับข้อมูลผลลัพธ์ของกระบวนการเด็ก จากนั้นนอกเหนือจากข้อมูลเอาต์พุตแล้วยังมีข้อมูลอินพุต เนื่องจากกระบวนการเด็กไม่มีคอนโซลของตัวเองข้อมูลอินพุตจะต้องจัดทำโดยกระบวนการหลักด้วย เราสามารถให้ข้อมูลอินพุตกับกระบวนการเด็กผ่านวิธีการของ GetOutputStream ของกระบวนการ (นั่นคือข้อมูลอินพุตจากกระบวนการพาเรนต์ไปยังกระบวนการเด็กแทนที่จะเป็นข้อมูลอินพุตจากคอนโซล) เราสามารถดูรหัสต่อไปนี้:
// test2.java นำเข้า Java.io.*; การทดสอบระดับสาธารณะ {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {bufferedreader br = bufferedreader ใหม่ (ใหม่ inputstreamread er (system.in)); "ข้อมูลที่ป้อนโดยกระบวนการหลัก:" + br.readline ());}} // test_exec_in.javaimport java.io.*; คลาสสาธารณะ test_exec_in {โมฆะคงที่สาธารณะ (สตริง [] args) .getRuntime (); flush( ); bw.close(); // The stream must be closed, otherwise information cannot be entered into the child process// System.in.read(); }} จากรหัสข้างต้นเราจะเห็นว่า test1 ได้รับข้อมูลที่ส่งโดย test_exec_in และส่งออก เมื่อคุณไม่เพิ่ม bw.flash () และ bw.close () ข้อมูลจะไม่ถึงกระบวนการเด็กซึ่งหมายความว่ากระบวนการเด็กจะเข้าสู่สถานะการปิดกั้น แต่เนื่องจากกระบวนการแม่ออกไป . หากคุณต้องการพิสูจน์สิ่งนี้คุณสามารถเพิ่ม System.in.read () ในตอนท้ายจากนั้นดูกระบวนการ Java ผ่านตัวจัดการงาน (ใต้ Windows) และคุณจะพบว่าหากคุณเพิ่ม bw.flush () และ bw .close () มีกระบวนการ Java เพียงอันเดียวเท่านั้นหากถูกลบออกจะมีกระบวนการ Java สองกระบวนการอยู่ นี่เป็นเพราะหากข้อมูลถูกส่งไปยัง Test2, Test2 ออกหลังจากได้รับข้อมูล นี่คือสิ่งหนึ่งที่ต้องอธิบายว่าการดำเนินการของ EXEC เป็นแบบอะซิงโครนัสและจะไม่หยุดการเรียกใช้รหัสต่อไปนี้เนื่องจากโปรแกรมบางอย่างที่ดำเนินการถูกบล็อก ดังนั้นหลังจากเรียกใช้ test2 รหัสต่อไปนี้ยังสามารถดำเนินการได้
วิธีการบริหารได้รับการโหลดซ้ำหลายครั้ง สิ่งที่ใช้ด้านบนเป็นเพียงการโอเวอร์โหลดของมัน นอกจากนี้ยังสามารถแยกคำสั่งและพารามิเตอร์เช่น exec ("java.test2") สามารถเขียนเป็น exec ("java", "test2") EXEC ยังสามารถเรียกใช้เครื่องเสมือน Java ที่มีการกำหนดค่าที่แตกต่างกันผ่านตัวแปรสภาพแวดล้อมที่ระบุ
นอกเหนือจากการใช้วิธีการบริหารของ Runtime เพื่อสร้างกระบวนการเด็กแล้วคุณยังสามารถสร้างกระบวนการเด็กผ่าน ProcessBuilder การใช้ ProcessBuilder มีดังนี้:
// test_exec_out.javaimport java.io.*; คลาสสาธารณะ test_exec_out {โมฆะสาธารณะคงที่หลัก (สตริง [] args) {processbuilder pb = processbui lder ใหม่ ("java", "test1"); ;ในการสร้างกระบวนการเด็ก ProcessBuilder นั้นคล้ายกับรันไทม์ หลังจากได้รับกระบวนการแล้วการดำเนินงานของพวกเขาจะเหมือนกันทุกประการ
เช่นเดียวกับรันไทม์ ProcessBuilder ยังสามารถตั้งค่าข้อมูลสภาพแวดล้อมไดเรกทอรีการทำงาน ฯลฯ ของไฟล์ปฏิบัติการ ตัวอย่างต่อไปนี้อธิบายวิธีการตั้งค่าข้อมูลนี้โดยใช้ ProcessBuilder
ProcessBuilder pb = processbuilder ใหม่ ("คำสั่ง", "arg2", "arg2", '' '); // ตั้งค่าตัวแปรสภาพแวดล้อม MAP <String, string> env = pb.environment (); env.put ("key1" ::::::::::::::::::::::: กระทาน ::::::::::::::::::::::: กระทาน :::::::::::::::::::::::::::::::::::::::: กระทาน. .get ("key1") + "_test");