أولاً ، دعنا نتحدث عن المعرفة المفاهيمية المتعلقة بالتطبيقات والعمليات في Java ، ثم شرح كيفية إنشاء مؤشرات الترابط وكيفية إنشاء العمليات. هنا هو الخطوط العريضة لهذا المقال:
1. مفاهيم المتعلقة بالتطبيقات والعمليات في جافا
2. كيفية إنشاء المواضيع في جافا
3. كيف لإنشاء عملية في جافا
1. مفاهيم المتعلقة بالتطبيقات والعمليات في جافا
في Java ، يتوافق التطبيق مع مثيل JVM (يسمى أيضًا عملية JVM) ، والاسم الافتراضي إلى java.exe أو javaw.exe (يمكن عرضه من خلال مدير المهام تحت Windows). تتبنى Java نموذجًا للبرمجة ذات الخيوط الواحدة ، أي إذا لم نقم بإنشاء مؤشرات ترابط بنشاط في برنامجنا الخاص ، فسنقوم بإنشاء سلسلة رسائل واحدة فقط ، والتي عادة ما تسمى الخيط الرئيسي. ولكن كن على دراية أنه على الرغم من وجود مؤشر ترابط واحد فقط لأداء المهام لا يعني أن هناك موضوع واحد فقط في JVM. عند إنشاء مثيل JVM ، سيتم إنشاء العديد من المواضيع الأخرى (مثل مؤشرات ترابط جامع القمامة).
نظرًا لأن Java تتبنى نموذجًا للبرمجة ذات الخيوط الواحدة ، عند برمجة واجهة المستخدم ، يجب أن تنتبه إلى وضع عمليات مستهلكة للوقت في مؤشر ترابط الطفل لتجنب حظر الخيط الرئيسي (عند برمجة واجهة المستخدم ، فإن الموضوع الرئيسي هو سلسلة واجهة المستخدم ، والتي يتم استخدامها للتعامل مع أحداث تفاعل المستخدم).
2. كيفية إنشاء المواضيع في جافا
إذا كنت ترغب في إنشاء مؤشر ترابط في Java ، فهناك عمومًا طريقتين: 1) ورث فئة الخيط ؛ 2) تنفيذ واجهة Runnable.
1. ورث فئة الخيط
إذا ورثت فئة الخيوط ، فيجب عليك تجاوز طريقة التشغيل وتحديد المهام التي تحتاج إلى تنفيذها في طريقة التشغيل.
الفئة myThread يمتد Thread {private static int num = 0 ؛ public mythread () {num ++ ؛ } Override public void run () {system.out.println ("تم إنشاؤه بشكل نشط"+num+"threads") ؛ }}بعد إنشاء فئة مؤشرات الترابط الخاصة بك ، يمكنك إنشاء كائن مؤشر ترابط ثم بدء تشغيل مؤشر الترابط من خلال طريقة Start (). لاحظ أنه لا يسمى طريقة Run () لبدء سلسلة الرسائل. تحدد طريقة التشغيل فقط المهام التي يجب تنفيذها. إذا تم استدعاء طريقة التشغيل ، فإنها تعادل تنفيذ طريقة التشغيل في الخيط الرئيسي ، والتي لا تختلف عن مكالمات الطريقة العادية. في هذا الوقت ، لن يتم إنشاء مؤشر ترابط جديد لتنفيذ المهام المحددة.
اختبار الفئة العامة {public static void main (string [] args) {mythread thread = new MyThread () ؛ thread.start () ؛ }} class myThread يمتد Thread {private static int num = 0 ؛ public mythread () {num ++ ؛ } Override public void run () {system.out.println ("تم إنشاؤه بشكل نشط"+num+"threads") ؛ }}في الكود أعلاه ، من خلال استدعاء طريقة START () ، سيتم إنشاء مؤشر ترابط جديد. من أجل التمييز بين الفرق بين مكالمات Method Start () ومكالمات التشغيل () ، يرجى الاطلاع على المثال التالي:
اختبار الفئة العامة {public static void main (string [] args) {system.out.println ("معرف الخيط الرئيسي:"+thread.currentThRead (). getId ()) ؛ MyThread thread1 = new MyThread ("thread1") ؛ thread1.start () ؛ MyThread thread2 = new MyThread ("Thread2") ؛ thread2.run () ؛ }} class myThread يمتد مؤشر الترابط {اسم السلسلة الخاصة ؛ public mythread (اسم السلسلة) {this.name = name ؛ } Override public void run () {system.out.println ("name:"+name+"child thread id:"+thread.currentThRead (). }}نتائج التشغيل:
من نتائج الإخراج ، يمكن استخلاص الاستنتاجات التالية:
1) تختلف معرفات مؤشر الترابط 1 و Thread2 ، ومرابط 2 ومعرف مؤشر الترابط الرئيسي هو نفسه ، مما يعني أن استدعاء طريقة التشغيل لن تنشئ مؤشر ترابط جديد ، ولكن سيتم تشغيل طريقة التشغيل مباشرة في مؤشر الترابط الرئيسي ، والتي لا تختلف عن مكالمات الطريقة العادية ؛
2) على الرغم من استدعاء طريقة بدء تشغيل Thread1 قبل طريقة تشغيل Thread2 ، إلا أن المعلومات حول استدعاء طريقة تشغيل Thread2 يتم إخراجها أولاً ، مما يشير إلى أن عملية إنشاء مؤشر ترابط جديد لن تمنع التنفيذ اللاحق للمعلومات الرئيسية.
2. تنفيذ واجهة Runnable
بالإضافة إلى وراثة فئة مؤشرات الترابط ، يمكن إنشاء مؤشرات ترابط في JAVA أيضًا تنفيذ وظائف مماثلة من خلال تنفيذ الواجهة القابلة للتشغيل. يجب أن يؤدي تطبيق الواجهة القابلة للتشغيل إلى تجاوز طريقة التشغيل الخاصة بها.
هنا مثال:
اختبار الفئة العامة {public static void main (string [] args) {system.out.println ("معرف الخيط الرئيسي:"+thread.currentThRead (). getId ()) ؛ myrunnable runnable = new myrunnable () ؛ موضوع الموضوع = مؤشر ترابط جديد (Runnable) ؛ thread.start () ؛ }} class myrunnable recrements {public myrunnable () {} override public void run () {system.out.println ("sub -brathread id:"+thread.currentThread (). getId ()) ؛ }}Runnable تعني "المهمة" باللغة الصينية. كما يوحي الاسم ، من خلال تطبيق الواجهة القابلة للتشغيل ، نقوم بتحديد المهام الفرعية ثم نسلح المهام الفرعية إلى مؤشر الترابط لتنفيذها. لاحظ أن هذه الطريقة يجب أن تستخدم RunNable كمعلمة لفئة مؤشرات الترابط ، ثم قم بإنشاء مؤشر ترابط جديد لتنفيذ المهام الفرعية من خلال طريقة بدء مؤشر الترابط. إذا تم استدعاء طريقة تشغيل RunNable ، فلن يتم إنشاء مؤشر ترابط جديد ، ولا يوجد فرق بين هذه المكالمة العادية.
في الواقع ، إذا نظرت إلى رمز مصدر التنفيذ لفئة مؤشرات الترابط ، فستجد أن فئة مؤشرات الترابط تنفذ واجهة Runnable.
في Java ، يمكن استخدام هاتين الطريقتين لإنشاء مؤشرات الترابط لتنفيذ المهام الفرعية. تعتمد الطريقة المحددة للاختيار على احتياجاتك. إذا ورثت مباشرة فئة مؤشرات الترابط ، فقد تبدو أكثر إيجازًا من تنفيذ الواجهة القابلة للتشغيل. ومع ذلك ، نظرًا لأن Java يسمح فقط بالميراث الفردي ، إذا احتاجت فئة مخصصة إلى وراثة فئات أخرى ، فيمكنك فقط اختيار تنفيذ الواجهة القابلة للتشغيل.
3. كيف لإنشاء عملية في جافا
في Java ، هناك طريقتان لإنشاء عمليات ، تتضمن ما مجموعه 5 فئات رئيسية.
الطريقة الأولى هي إنشاء عملية من خلال طريقة التشغيل. دعنا نتحدث عن الاختلافات والاتصالات بين هاتين الطريقتين.
أول شيء أريد التحدث عنه هو فئة العملية. فئة العملية هي فئة مجردة. هناك أساسا العديد من الأساليب المجردة في ذلك. يمكنك تعلم ذلك من خلال النظر في الكود المصدري لفئة العملية:
يقع في مسار Java.lang.Process:
اختبار الفئة العامة {public static void main (string [] args) {system.out.println ("معرف الخيط الرئيسي:"+thread.currentThRead (). getId ()) ؛ myrunnable runnable = new myrunnable () ؛ موضوع الموضوع = مؤشر ترابط جديد (Runnable) ؛ thread.start () ؛ }} class myrunnable recrements {public myrunnable () {} override public void run () {system.out.println ("sub -brathread id:"+thread.currentThread (). getId ()) ؛ }}1) قم بإنشاء عملية من خلال ProcessBuilder
ProcessBuilder هو فئة نهائية بها مُنشئان:
Public Class ProcessBuilder {Private List <string> command ؛ دليل الملف الخاص ؛ خريطة خاصة <سلسلة ، سلسلة> بيئة ؛ إعادة صياغة منطقية خاصة ؛ Public ProcessBuilder (قائمة <Tring> الأمر) {if (command == null) رمي nullpointerxception () ؛ this.command = command ؛ } Public ProcessBuilder (string ... command) {this.command = new ArrayList <string> (command.length) ؛ لـ (سلسلة arg: command) this.command.add (arg) ؛ } ......}يمرر المنشئ معلمات الأوامر للعملية التي يجب إنشاؤها. يضع المُنشئ الأول معلمات الأوامر في القائمة ويمررها في شكل سلسلة طويلة إلى أجل غير مسمى.
لذلك دعونا نستمر في النظر إلى أسفل. كما ذكرنا سابقًا ، نقوم بإنشاء عملية جديدة من خلال طريقة بدء تشغيل ProcessBuilder. دعنا نلقي نظرة على ما يتم القيام به بالضبط في طريقة البداية. فيما يلي رمز مصدر التنفيذ المحدد لطريقة البدء:
START العملية العامة start () يلقي ioException {// يجب تحويل إلى صفيف أولاً-قد تحاول قائمة ضارة من قبل المستخدم // أن تحاول دائرة Check.String [] cmdarray = command.toarray (new string [command.size ()]) PRANGESTRING PROG = CMDARRAY [0] ؛ SecurityManager Security = System.GetSecurityManager () ؛ if (Security! = null) Security.Checkexec (prog) ؛ سلسلة dir = دليل == فارغ؟ NULL: DIRECTORY.TOSTRING () ؛ جرب {Return ProcessImpl.Start (cmdarray ، البيئة ، dir ، redirecterrorstream) ؛} catch (ioException e) {// من الأسهل بالنسبة لنا إنشاء خطأ / رسالة عالية الجودة من رمز c المنخفض المستوى الذي وجد المشكلة. رمي iOexception جديد ("لا يمكن تشغيل البرنامج /" " + prog +" /"" + (dir == null؟ ":" (في الدليل /"" + dir + " /")) + ":" + e.getMessage () ، e) ؛}}هذه الطريقة إرجاع كائن العملية. الجزء الأول من الطريقة يعادل تعيين بعض المعلمات بناءً على معلمات الأوامر ودليل العمل المحدد. أهم شيء هو جملة في كتلة بيان المحاولة:
Return ProcessImpl.start (Cmdarray ، Environment ، DIR ، RedirecterRorStream) ؛
هذه هي الجملة التي تخلق العملية حقًا. لاحظ أن طريقة البدء لفئة ProcessImpl تسمى. هنا يمكننا أن نعرف أن البداية يجب أن تكون طريقة ثابتة. إذن أي نوع من ProcessImpl هو؟ يقع هذا الفئة أيضًا في مسار Java.lang.ProcessImpl. دعنا نلقي نظرة على التنفيذ المحدد لهذا الفئة:
ProcessImpl هي أيضًا فئة نهائية ترث فئة العملية:
يمتد ProcessImpl النهائي للعملية {// system-dependent part of processbuilder.start () static process start (String cmdarray [] ، java.util.map <string ، string> ecorder ، string dir ، boolean redirecterrorstream) يلقي iOexception {string envblock = processenvironment.toenvironment. إرجاع ProcessImpl جديد (cmdarray ، envblock ، dir ، redirecterrorstream) ؛ } ....}هذا هو التنفيذ المحدد لطريقة البدء لفئة ProcessImpl. في الواقع ، يتم استخدام هذه الجملة لإنشاء كائن ProcessImpl:
إرجاع ProcessImpl جديد (cmdarray ، envblock ، dir ، redirecterrorstream) ؛
في ProcessImpl ، يتم تنفيذ العديد من الأساليب المجردة في فئة العملية في التنفيذ الملموس.
في الواقع ، يتم إنشاء كائن ProcessImpl من خلال طريقة بدء تشغيل ProcessBuilder.
دعنا نلقي نظرة على مثال استخدام ProcessBuilder لإنشاء عملية. على سبيل المثال ، إذا كنت أرغب في بدء عملية من خلال ProcessBuilder لفتح CMD والحصول على معلومات عنوان IP ، فيمكنني كتابتها مثل هذا:
اختبار الفئة العامة {public static void main (string [] args) يلقي ioException {ProcessBuilder pb = new ProcessBuilder ("cmd" ، "/c" ، "ipConfig/all") ؛ عملية العملية = pb.start () ؛ الماسح الضوئي = الماسح الضوئي الجديد (process.getInputStream ()) ؛ بينما (scanner.hasNextLine ()) {system.out.println (Scanner.nextLine ()) ؛ } scanner.close () ؛ }}الخطوة الأولى هي الأكثر أهمية ، وهي تمرير سلسلة الأوامر إلى مُنشئ ProcessBuilder. بشكل عام ، يتم استخدام كل أمر مستقل في السلسلة كمعلمة منفصلة ، ولكن يمكن أيضًا وضعه في القائمة بالترتيب وتمريره.
أما بالنسبة للعديد من الاستخدامات المحددة الأخرى ، فلن أشرحها هنا ، مثل تعيين متغيرات بيئة العملية وأدلة العمل من خلال طريقة البيئة ودليل ProcessBuilder (دليل الملفات). يمكن للأصدقاء المهتمين عرض مستندات API ذات الصلة.
2) إنشاء عملية من خلال طريقة EXEC في وقت التشغيل
أولاً ، دعونا نلقي نظرة على التنفيذ المحدد لفئة وقت التشغيل وطريقة EXEC. يمثل وقت التشغيل ، كما يوحي الاسم ، التشغيل ، مثيل الجهاز الظاهري حيث توجد العملية الحالية.
نظرًا لأن أي عملية ستعمل فقط في مثيل واحد من الجهاز الظاهري ، يتم استخدام وضع Singleton في وقت التشغيل ، أي أنه سيتم إنشاء مثيل جهاز افتراضي واحد فقط:
وقت تشغيل الفئة العامة {private Static Runtime CurrentRuntime = new Runtime () ؛ /*** إرجاع كائن وقت التشغيل المرتبط بتطبيق Java الحالي. * معظم طرق الفئة <code> وقت التشغيل </code> هي أساليب مثيل * ويجب استدعاؤها فيما يتعلق بكائن وقت التشغيل الحالي. * * regurn الكائن <code> Runtime </code> المرتبط بتطبيق Java الحالي *. */ public static وقت التشغيل getRuntime () {return currentRuntime ؛ } / ** لا تدع أي شخص آخر على إنشاء إنشاء هذا الفئة* / private Runtime () {} ...}من هنا ، يمكننا أن نرى أنه نظرًا لأن مُنشئ فئة وقت التشغيل خاص ، يمكننا فقط الحصول على مثيل وقت التشغيل من خلال GetRuntime. بعد ذلك ، دعونا نلقي نظرة فاحصة على تطبيق طريقة EXEC. هناك العديد من تطبيقات التحميل الزائد المختلفة لـ EXEC في وقت التشغيل ، ولكن نهاية التنفيذ هي هذا الإصدار من طريقة EXEC:
العملية العامة exec (String [] cmdarray ، string [] envp ، file dir) يلقي ioException {return new ProcessBuilder (cmdarray) .environment (envp) .Directory (dir) .start () ؛ }يمكن العثور على أنه في الواقع ، إذا تم إنشاء العملية من خلال exec من فئة وقت التشغيل ، يتم إنشاؤها في النهاية من خلال طريقة البدء لفئة ProcessBuilder.
دعنا نلقي نظرة على مثال لمعرفة كيفية إنشاء عملية من خلال EXEC في وقت التشغيل ، أو المثال السابق ، اتصل بـ CMD للحصول على معلومات عنوان IP:
اختبار الفئة العامة {public static void main (string [] args) يلقي ioException {String cmd = "cmd"+"/c"+"ipConfig/all" ؛ عملية العملية = Runtime.getRuntime (). الماسح الضوئي = الماسح الضوئي الجديد (process.getInputStream ()) ؛ بينما (scanner.hasNextLine ()) {system.out.println (Scanner.nextLine ()) ؛ } scanner.close () ؛ }}تجدر الإشارة إلى أن طريقة EXEC لا تدعم المعلمات ذات الطول غير المحدد (تدعم ProcessBuilder معلمات الطول غير المحددة) ، لذلك يجب تقطيع معلمات الأوامر أولاً قبل تمريرها.
سأتحدث عن كيفية إنشاء المواضيع والعمليات في جافا في الوقت الحالي. يمكن للأصدقاء المهتمين الرجوع إلى المعلومات ذات الصلة.