JavaRush /مدونة جافا /Random-AR /تعدد مؤشرات الترابط: ما تفعله أساليب فئة الموضوع

تعدد مؤشرات الترابط: ما تفعله أساليب فئة الموضوع

نشرت في المجموعة
مرحبًا! اليوم نواصل الحديث عن تعدد المواضيع. دعونا نلقي نظرة على فئة Thread وكيفية عمل طرقها المتعددة. في السابق، عندما درسنا الأساليب الصفية، غالبًا ما كنا نكتبها ببساطة على النحو التالي: "اسم الطريقة" -> "ماذا تفعل".
تعدد مؤشرات الترابط: ما تفعله أساليب فئة الموضوع - 1
لن ينجح هذا مع طرق الخيط :) منطقها أكثر تعقيدًا، ومن المستحيل فهمه بدون عدة أمثلة.

طريقة Thread.start()

لنبدأ بالتكرار. كما تتذكر على الأرجح، يمكنك إنشاء سلسلة رسائل عن طريق وراثة فصلك من الفصل Threadوتجاوز الطريقة الموجودة فيه run(). لكن، بالطبع، لن يبدأ الأمر من تلقاء نفسه. للقيام بذلك، نسمي الطريقة على كائننا start(). تعدد مؤشرات الترابط: ما تفعله أساليب فئة الموضوع - 2ولنتذكر المثال من المحاضرة السابقة:
public class MyFirstThread extends Thread {

   @Override
   public void run() {
       System.out.println("Выполнен поток " + getName());
   }
}


public class Main {

   public static void main(String[] args) {

       for (int i = 0; i < 10; i++) {
           MyFirstThread thread = new MyFirstThread();
           thread.start();
       }
   }
}
يرجى ملاحظة: لبدء سلسلة محادثات، يجب عليك استدعاء الطريقة الخاصةstart()، وليسrun()! من السهل ارتكاب هذا الخطأ، خاصة عند تعلم تعدد العمليات لأول مرة. إذا قمت في مثالنا باستدعاء تابع الكائنrun()بدلًا منstart()، فستكون النتيجة كما يلي:
public class Main {

   public static void main(String[] args) {

       for (int i = 0; i < 10; i++) {
           MyFirstThread thread = new MyFirstThread();
           thread.run();
       }
   }
}
تم تنفيذ الخيط -0 تم تنفيذ الخيط -1 تم تنفيذ الخيط -2 تم ​​تنفيذ الخيط -3 تم تنفيذ الخيط -4 تم تنفيذ الخيط -5 تم تنفيذ الخيط -6 تم تنفيذ الخيط -7 تم تنفيذ الخيط -8 تم تنفيذ الخيط -9 انظر إلى تسلسل الإخراج: كل شيء يسير على ما يرام. غريب، أليس كذلك؟ نحن لسنا معتادين على ذلك، لأننا نعلم بالفعل أن الترتيب الذي يتم به إطلاق سلاسل الرسائل وتنفيذها يتم تحديده من خلال الذكاء الفائق داخل نظام التشغيل لدينا - برنامج جدولة سلاسل الرسائل. ربما كنت محظوظا فقط؟ بالطبع، إنها ليست مسألة حظ. يمكنك التحقق من ذلك عن طريق تشغيل البرنامج عدة مرات. النقطة المهمة هي أن استدعاء الطريقة مباشرةrun()لا علاقة له بتعدد مؤشرات الترابط. في هذه الحالة، سيتم تنفيذ البرنامج في الموضوع الرئيسي - الذي يتم فيه تنفيذ الطريقةmain(). سوف يقوم ببساطة بإخراج 10 أسطر بالتتابع إلى وحدة التحكم وهذا كل شيء. لن يبدأ أي 10 مواضيع. لذلك، تذكر للمستقبل وتحقق باستمرار من نفسك. إذا كنت تريد أن يتم ذلكrun()، اتصل بهstart(). هيا لنذهب.

طريقة Thread.sleep()

لإيقاف تنفيذ مؤشر الترابط الحالي مؤقتًا لبعض الوقت، استخدم الأمر sleep(). تعدد مؤشرات الترابط: ما تفعله أساليب فئة الموضوع - 3تأخذ الطريقة sleep()كمعلمة عدد المللي ثانية، أي الوقت الذي يحتاج فيه الخيط إلى وضع السكون.
public class Main {

   public static void main(String[] args) throws InterruptedException {

       long start = System.currentTimeMillis();

       Thread.sleep(3000);

       System.out.println(" - Сколько я проспал? \n - " + ((System.currentTimeMillis()-start)) / 1000 + " секунды");

   }
}
إخراج وحدة التحكم: - كم من الوقت نمت؟ - 3 ثوانٍ يرجى ملاحظة: الطريقة sleep()ثابتة: فهي تضع الخيط الحالي في وضع السكون. وهذا هو، الذي يعمل في الوقت الراهن. فارق بسيط آخر مهم: يمكن مقاطعة التدفق في حالة النوم. في هذه الحالة، سيحدث استثناء في البرنامج InterruptedException. سننظر إلى مثال أدناه. بالمناسبة، ماذا يحدث بعد أن "يستيقظ" الخيط؟ فهل سيواصل تنفيذه على الفور من حيث توقف؟ لا. بعد أن يستيقظ الخيط - عندما ينتهي الوقت كوسيطة لانتهاء الصلاحية Thread.sleep()- فإنه يدخل في حالة التشغيل . ومع ذلك، هذا لا يعني أن برنامج جدولة مؤشر الترابط سيقوم بتشغيله. من الممكن أن يعطي الأفضلية لبعض الخيوط الأخرى "غير النائمة"، وسيستمر خيطنا "المستيقظ حديثًا" في العمل بعد ذلك بقليل. تأكد من أن تتذكر: "الاستيقاظ لا يعني الاستمرار في العمل في تلك اللحظة بالذات!"

طريقة Thread.join()

تعدد مؤشرات الترابط: ما تفعله أساليب فئة الموضوع - 4تقوم الطريقة join()بتعليق تنفيذ مؤشر الترابط الحالي حتى اكتمال مؤشر ترابط آخر. إذا كان لدينا خيطين، t1و t2، ونكتب -
t1.join()
t2لن يبدأ العمل حتى يكمل t1 عمله. يمكن استخدام هذه الطريقة join()لضمان تسلسل تنفيذ الخيوط. دعونا نلقي نظرة على العمل join()باستخدام مثال:
public class ThreadExample extends Thread {

   @Override
   public void run() {

       System.out.println("Начало работы потока " + getName());

       try {
           Thread.sleep(5000);
       } catch (InterruptedException e) {
           e.printStackTrace();
       }
       System.out.println("Поток " + getName() +  " завершил работу.");
   }
}


public class Main {

   public static void main(String[] args) throws InterruptedException {

       ThreadExample t1 = new ThreadExample();
       ThreadExample t2 = new ThreadExample();

       t1.start();


 /*Второй поток t2 начнет выполнение только после того, How будет завершен
       (or бросит исключение) первый поток - t1*/
       try {
           t1.join();
       } catch (InterruptedException e) {
           e.printStackTrace();
       }

       t2.start();

       //Главный поток продолжит работу только после того, How t1 и t2 завершат работу
       try {
           t1.join();
           t2.join();
       } catch (InterruptedException e) {
           e.printStackTrace();
       }

       System.out.println("Все потоки закончor работу, программа завершена");

   }
}
لقد أنشأنا فئة بسيطة ThreadExample. وتتمثل مهمتها في عرض رسالة على الشاشة حول بدء العمل، ثم النوم لمدة 5 ثواني وفي النهاية الإبلاغ عن الانتهاء من العمل. لا شيء معقد. المنطق الرئيسي موجود في الفصل Main. انظر إلى التعليقات: باستخدام هذه الطريقة، join()نجحنا في التحكم في تسلسل تنفيذ الخيوط. إذا كنت تتذكر بداية الموضوع، فإن برنامج جدولة الموضوع هو الذي قام بذلك. لقد أطلقها وفقًا لتقديره الخاص: بشكل مختلف في كل مرة. هنا، باستخدام هذه الطريقة، تأكدنا من تشغيل الخيط وتنفيذه أولاً t1، ثم الخيط t2، وبعد ذلك فقط الخيط الرئيسي لتنفيذ البرنامج. تفضل. في البرامج الحقيقية، غالبا ما تواجه المواقف عندما تحتاج إلى مقاطعة تنفيذ بعض المواضيع. على سبيل المثال، مؤشر الترابط الخاص بنا قيد التشغيل، ولكنه ينتظر استيفاء حدث أو شرط معين. إذا حدث هذا، فإنه يتوقف. ربما يكون من المنطقي لو كانت هناك طريقة مثل stop(). ومع ذلك، كل شيء ليس بهذه البساطة. ذات مرة، Thread.stop()كانت هناك طريقة في Java بالفعل وتسمح لك بمقاطعة عمل سلسلة ما. ولكن تمت إزالته لاحقًا من مكتبة Java. يمكنك البحث عنه في وثائق Oracle ورؤية أنه تم وضع علامة عليه كمهمل . لماذا؟ لأنه ببساطة أوقف التدفق دون أي عمل إضافي. على سبيل المثال، يمكن أن يعمل الخيط مع البيانات ويغير شيئًا ما فيها. ثم فقد وعيه فجأة stop()في منتصف العمل - وكان هذا كل شيء. لم يكن هناك إيقاف تشغيل صحيح، ولا تحرير للموارد، ولا حتى معالجة للأخطاء - لم يحدث أي من هذا. هذه الطريقة stop()، على سبيل المبالغة، دمرت ببساطة كل شيء في طريقها. يمكن مقارنة عملها بالطريقة التي يقوم بها شخص ما بسحب القابس من المقبس لإيقاف تشغيل الكمبيوتر. نعم يمكنك تحقيق النتيجة المرجوة. لكن الجميع يفهم أنه في غضون أسبوعين لن يقول الكمبيوتر "شكرًا لك" على هذا. لهذا السبب، تم تغيير منطق مقاطعة المواضيع في Java، والآن يتم استخدام طريقة خاصة - interrupt().

طريقة Thread.interrupt()

ماذا يحدث إذا قمت باستدعاء طريقة interrupt() على موضوع ؟ هناك خياران:
  1. إذا كان الكائن في حالة الانتظار في تلك اللحظة، على سبيل المثال، joinأو sleep، فسيتم مقاطعة الانتظار وسيقوم البرنامج برمي InterruptedException.
  2. إذا كان الخيط في حالة عمل في تلك اللحظة، فسيتم تعيين العلامة المنطقية للكائن interrupted.
ولكن سيتعين علينا التحقق من الكائن لمعرفة قيمة هذا العلم وإكمال العمل بشكل صحيح بأنفسنا! ولهذا الغرض، Threadلدى الفصل طريقة خاصة - boolean isInterrupted(). دعنا نعود إلى مثال الساعة من محاضرة الدورة الرئيسية. للراحة، تم تبسيطها قليلاً:
public class Clock extends Thread {

   public static void main(String[] args) throws InterruptedException {
       Clock clock = new Clock();
       clock.start();

       Thread.sleep(10000);
       clock.interrupt();
   }

   public void run() {
       Thread current = Thread.currentThread();

       while (!current.isInterrupted())
       {
           try {
               Thread.sleep(1000);
           } catch (InterruptedException e) {
               System.out.println("Работа потока была прервана");
               break;
           }
           System.out.println("Tik");
       }
   }
}
في حالتنا، تبدأ الساعة وتبدأ بالدق كل ثانية. في الثانية العاشرة نقطع تدفق الساعة. كما تعلم بالفعل، إذا كان الخيط الذي نحاول مقاطعته في إحدى حالات الانتظار، فسيؤدي ذلك إلى InterruptedException. هذا النوع من الاستثناءات هو استثناء محدد، بحيث يمكن اكتشافه بسهولة وتنفيذ منطق إنهاء البرنامج الخاص بنا. هذا ما فعلناه. ها هي نتيجتنا: تيك تيك تيك تيك تيك تيك تيك تيك تيك انقطع عمل الخيط، وبهذا نختتم مقدمتنا للطرق الرئيسية للفصل Thread. لتعزيز معرفتك، يمكنك مشاهدة محاضرة الفيديو هذه حول تعدد العمليات:
سيكون بمثابة مادة إضافية ممتازة! في النهاية، بعد إلقاء نظرة عامة على الأساليب، فإنه يوضح بالضبط ما سنتناوله لاحقًا في الدورة :) حظًا سعيدًا!
تعليقات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION