بشكل عام ، عندما نقوم بتشغيل طرق في فئات أخرى في Java ، سواء كانت مكالمات ثابتة أو ديناميكية ، يتم تنفيذها في العملية الحالية ، أي أن هناك مثيلًا واحدًا من الجهاز الظاهري Java يعمل. في بعض الأحيان ، نحتاج إلى بدء عمليات تخفيضات متعددة Java من خلال كود Java. على الرغم من أن هذا الأمر يتناول بعض موارد النظام ، إلا أنه سيجعل البرنامج أكثر استقرارًا لأن البرنامج الذي بدأه تم تشغيله حديثًا في عمليات آلية افتراضية مختلفة.
في Java يمكننا استخدام طريقتين لتحقيق هذا المطلب. أسهل طريقة هي تنفيذ اسم Java ClassName من خلال طريقة EXEC في وقت التشغيل. إذا كان التنفيذ ناجحًا ، فإن هذه الطريقة تُرجع كائن العملية. لنلقي نظرة على مثال بسيط أدناه.
// test1.java file import java.io.*؛ اختبار الفئة العامة {public static void main (string [] args) {fileOtputStream fout = new FileOutputStream ("c: // test1 .txt") ؛ fout.close () ؛ 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 ، وجدت أن هناك ملف Test1.txt إضافي على محرك C ، لكن معلومات الإخراج "تسمى بنجاح!" لذلك ، يمكن استنتاج أن الاختبار قد تم تنفيذه بنجاح ، ولكن لسبب ما ، لا يتم إخراج معلومات الإخراج من الاختبار في وحدة التحكم في Test_Exec. هذا السبب بسيط للغاية ، لأن عملية الطفل Test_exec يتم إنشاؤها باستخدام EXEC.
إذا كنت ترغب في إخراج معلومات الإخراج من عملية الطفل ، فيمكنك الحصول على دفق الخرج لعملية الطفل من خلال GetInputStream في العملية (الإخراج في عملية الطفل ، والإدخال في العملية الأصل) ، ثم نقل دفق الخرج للطفل العملية من إخراج وحدة التحكم في العملية. رمز التنفيذ المحدد كما يلي:
// test_exec_out.javaimport java.io.*؛ فئة عامة test_exec_out {public static void main (string [] = جديد bufferedInputStream (p.getInputStream ()) ؛ Bufferreader BR = جديد BufferedReader (new inputStreamReader (in)) ؛ string s ؛ ؛}}
كما يتضح من الكود أعلاه ، في test_exec_out.java ، تتم قراءة معلومات الإخراج من عملية الطفل بواسطة الصف ، ثم يتم تنفيذ الإخراج في كل سطر في test_exec_out. المناقشة أعلاه هي كيفية الحصول على معلومات الإخراج من عملية الطفل. ثم ، بالإضافة إلى معلومات الإخراج ، هناك أيضًا معلومات إدخال. نظرًا لأن عملية الطفل لا تحتوي على وحدة تحكم خاصة بها ، يجب أيضًا توفير معلومات الإدخال من قبل العملية الأصل. يمكننا توفير معلومات الإدخال لعملية الطفل من خلال طريقة عملية GetOutputStream (أي معلومات الإدخال من العملية الأصل إلى عملية الطفل ، بدلاً من معلومات الإدخال من وحدة التحكم). يمكننا أن ننظر إلى الكود التالي:
// test2.java file import 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 غير متزامن ولن يتوقف عن تنفيذ الكود التالي لأنه يتم حظر برنامج معين يتم تنفيذه. لذلك ، بعد تشغيل Test2 ، لا يزال من الممكن تنفيذ الكود التالي.
تم إعادة تحميل طريقة EXEC عدة مرات. ما هو مستخدم أعلاه هو مجرد حمولة زائدة منه. يمكن أيضًا فصل الأوامر والمعلمات ، مثل exec ("java.test2") يمكن كتابتها على أنها exec ("Java" ، "Test2"). يمكن لـ EXEC أيضًا تشغيل أجهزة Java الظاهرية مع تكوينات مختلفة من خلال متغيرات البيئة المحددة.
بالإضافة إلى استخدام طريقة EXEC في وقت التشغيل لبناء عملية طفل ، يمكنك أيضًا إنشاء عملية طفل من خلال ProcessBuilder. إن استخدام ProcessBuilder هو كما يلي:
// 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 () ؛عند إنشاء عمليات الطفل ، يشبه ProcessBuilder وقت التشغيل. بعد الحصول على العملية ، عملياتها هي نفسها بالضبط.
مثل وقت التشغيل ، يمكن لـ ProcessBuilder أيضًا تعيين معلومات البيئة ، ودليل العمل ، إلخ. من الملف القابل للتنفيذ. يصف المثال التالي كيفية تعيين هذه المعلومات باستخدام ProcessBuilder.
ProcessBuilder pb = new ProcessBuilder ("command" ، "arg2" ، "arg2" ، '' ') ؛ // set البيئة خريطة متغير <string ، env> env = pb.environment () ؛ env.put ("key1" ، ::::::::::::::::::::::::: :::::::::::::::::::::: ::::::::::::::::::::::::: :::::::::::::::::::::: ::::::::::::::::::::::::::::: ::::: "value1") ؛ env.remove ("key2") ؛ env.put ("key2" ، env (env . مشكلة حظر العملية
لا تعمل العمليات التي تمثلها في بعض الأحيان بشكل جيد على بعض المنصات ، خاصةً عند العمل على تدفقات الإدخال القياسية ، ومخرجات الخطأ التي تمثل العمليات.
إذا تم تعديل العبارة الواردة في المثال أعلاه والتي تعيد قراءة المعلومات من الإخراج القياسي للقراءة من دفق إخراج الخطأ:
stdout = جديد bufferedReader (new inputStreamReader (p.geterRorStream ())) ؛
ثم سيتم حظر البرنامج ولا يمكن تنفيذه ، ولكن شنق هناك.
عند بدء العملية ، يتم تشغيل دفق الإخراج القياسي ودفق إخراج الخطأ لإعداد الإخراج ، وعندما تنتهي العملية ، يتم إغلاقها. في المثال أعلاه ، لا يحتوي دفق إخراج الخطأ على بيانات لا يمكن إخراجها ، ويحتوي دفق الإخراج القياسي على إخراج البيانات. نظرًا لأن البيانات في دفق الإخراج القياسي لا تنتهي ، فلن يتم إغلاق دفق إخراج الخطأ. لحل هذه المشكلة ، يمكنك أولاً قراءة دفق الإخراج القياسي ثم قراءة دفق الإخراج الخاطئ وفقًا للترتيب الفعلي للإخراج.
ومع ذلك ، في كثير من الحالات ، لا يمكن أن يكون تسلسل الإخراج معروفًا بوضوح ، خاصةً عند الحاجة إلى الإدخال القياسي ، سيكون الموقف أكثر تعقيدًا. في هذا الوقت ، يمكن استخدام مؤشرات الترابط لمعالجة الإخراج القياسي وإخراج الخطأ والإدخال القياسي بشكل منفصل ، ويمكن قراءة الدفق أو البيانات وفقًا لعلاقة منطق الأعمال.
بالنسبة للمشاكل التي تسببها تدفقات الإخراج القياسية وتدفقات الإخراج الخاطئة ، يمكنك استخدام طريقة RedirecterRorsream () لتجمعها في هذا الوقت.
عند استخدام طريقة Waitfor () للعملية في البرنامج ، خاصة عند استدعاء طريقة Waitfor () قبل القراءة ، فقد يتسبب ذلك أيضًا في انسداد. يمكنك استخدام طرق مؤشر الترابط لحل هذه المشكلة ، أو يمكنك استدعاء طريقة Waitfor () بعد قراءة البيانات لانتظار انتهاء البرنامج.
باختصار ، أقدم هنا استخدام فئة ProcessBuilder ، باستخدام طريقة RediRecterRorStream لدمج دفق الإخراج القياسي ودفق إخراج الخطأ في واحدة. ، ثم اتصل بـ Waitfor () طريقة الانتظار حتى تنتهي العملية.
يحب:
استيراد java.io.bufferread {TRIME <STRING> LIST = NEW ARRAYLIST إضافة (CMD.exe ") ؛ ) ؛ (line = stdout.Readline ())! = null) {system.out.println (line) ؛ stdou t .close () ؛