it-swarm.asia

معالجة InterruptedException في Java

ما هو الفرق بين الطرق التالية للتعامل مع InterruptedException؟ ما هي أفضل طريقة للقيام بذلك؟

try{
 //...
} catch(InterruptedException e) { 
   Thread.currentThread().interrupt(); 
}

OR

try{
 //...
} catch(InterruptedException e) {
   throw new RuntimeException(e);
}

تحرير: أود أن أعرف أيضا في السيناريوهات التي تستخدم هذين.

254
devnull

كما يحدث ، كنت فقط أقرأ هذا الصباح في طريقي إلى العمل في Java Concurrency In Practice by Brian Goetz. في الأساس يقول يجب عليك القيام بأحد شيئين

  1. نشر InterruptedException- قم بتعريف طريقتك لإلقاء علامة InterruptedException المحددة بحيث يتوجب على المتصل بك التعامل معها.

  2. استعادة المقاطعة - في بعض الأحيان لا يمكنك رمي InterruptedException. في هذه الحالات ، يجب عليك التقاط InterruptedException واستعادة حالة المقاطعة عن طريق استدعاء الأسلوب interrupt() على currentThread حتى يتمكن الرمز أعلى مكدس الاستدعاءات من رؤية إصدار المقاطعة.

84
mR_fr0g

ماذا تحاول أن تفعل؟

يتم طرح InterruptedException عندما يكون مؤشر ترابط قيد الانتظار أو السكون ويقوم مؤشر ترابط آخر بمقاطعته باستخدام الأسلوب interrupt في الفئة Thread. لذلك إذا لاحظت هذا الاستثناء ، فهذا يعني أن مؤشر الترابط قد تمت مقاطعة. عادة لا توجد فائدة في استدعاء Thread.currentThread().interrupt(); مرة أخرى ، إلا إذا كنت تريد التحقق من حالة "المقاطعة" لمؤشر الترابط من مكان آخر.

فيما يتعلق بخيارك الآخر المتمثل في رمي RuntimeException ، لا يبدو من الحكمة القيام به (من سيصطاد هذا؟ كيف سيتم التعامل معه؟) ولكن من الصعب معرفة المزيد دون معلومات إضافية.

17
Grodriguez

بالنسبة لي ، فإن الشيء الرئيسي في هذا الأمر هو: إن InterruptedException لا يحدث أي خطأ ، بل هو مؤشر الترابط الذي يفعل ما قلته للقيام به. لذلك فإن إعادة رميها ملفوفة في RuntimeException لا معنى لها.

في كثير من الحالات ، يكون من المنطقي إعادة تقديم استثناء ملفوف في RuntimeException عندما تقول ، لا أدري ما الخطأ الذي حدث هنا ولا يمكنني فعل أي شيء لإصلاحه ، أريد فقط الخروج من تدفق المعالجة الحالي وضرب أي معالج استثناء على مستوى التطبيق لدي حتى يتمكن من تسجيل الدخول. ليس هذا هو الحال مع InterruptedException ، إنه مجرد مؤشر ترابط يستجيب إلى وجود مقاطعة () تم استدعاؤه ، إنه يرمي InterruptedException للمساعدة في إلغاء معالجة مؤشر الترابط في الوقت المناسب.

لذلك قم بنشر InterruptedException ، أو أكله بذكاء (وهذا يعني في مكان سيكون فيه قد أنجز ما كان من المفترض القيام به) وإعادة تعيين إشارة المقاطعة. لاحظ أنه يتم مسح علامة المقاطعة عندما يتم طرح InterruptedException؛ الافتراض الذي يطرحه مطورو مكتبة Jdk هو أن الحصول على الاستثناء يصل إلى حد معالجته ، لذلك يتم إزالة العلم افتراضيًا.

من المؤكد أن الطريقة الأولى هي الأفضل ، والمثال الذي تم نشره في السؤال ليس مفيدًا إلا إذا كنت لا تتوقع أن ينقطع مؤشر الترابط فعليًا ، ومقاطعته ترقى إلى خطأ.

إليك إجابة كتبت تصف كيفية عمل المقاطعات ، مع مثال . يمكنك أن ترى في رمز المثال حيث يستخدم InterruptedException لإنقاذ حلقة من الوقت في طريقة التشغيل Runnable.

12
Nathan Hughes

الخيار الافتراضي الصحيح هو إضافة InterruptedException إلى قائمة الرميات. تشير المقاطعة إلى أن سلسلة رسائل أخرى ترغب في إنهاء سلسلة الرسائل. سبب هذا الطلب ليس واضحًا وسياقيًا تمامًا ، لذا إذا لم يكن لديك أي معرفة إضافية ، فيجب أن تفترض أنها مجرد إيقاف تشغيل مألوف ، وأي شيء يتجنب هذا الإغلاق هو استجابة غير ودية.

لن تقوم Java بإلقاء تطبيق InterruptedException عشوائيًا ، فلن تؤثر جميع النصائح على التطبيق الخاص بك لكنني واجهت حالة أصبح فيها المطور الذي يتبع استراتيجية "الابتلاع" غير مريح للغاية. قام فريق بتطوير مجموعة كبيرة من الاختبارات واستخدم Thread.Sleep كثيرًا. الآن بدأنا في تشغيل الاختبارات في خادم CI الخاص بنا ، وأحيانًا بسبب العيوب الموجودة في الكود ستنتظر الانتظار الدائم. لجعل الموقف أكثر سوءًا ، عند محاولة إلغاء مهمة CI ، لم يتم إغلاقها أبدًا لأن مؤشر الترابط. المقصود منه إجهاض الاختبار لم يجهض المهمة. كان علينا تسجيل الدخول إلى المربع وقتل العمليات يدويًا.

قصة قصيرة جدًا ، إذا قمت ببساطة بطرح InterruptedException ، فأنت تتطابق مع الهدف الافتراضي الذي يجب أن ينتهي به مؤشر الترابط. إذا لم تتمكن من إضافة InterruptedException إلى قائمة الإلقاء الخاصة بك ، فسوف أقوم بلفها في RuntimeException.

هناك حجة عقلانية للغاية يجب أن تكون أن InterruptedException يجب أن يكون RuntimeException نفسه ، لأن ذلك من شأنه أن يشجع معالجة "افتراضية" أفضل. إنها ليست RuntimeException فقط لأن المصممين يتمسكون بقاعدة قاطعة وهي أن RuntimeException يجب أن يمثل خطأ في التعليمات البرمجية الخاصة بك. نظرًا لأن InterruptedException لا ينشأ مباشرةً من خطأ في التعليمات البرمجية الخاصة بك ، فهو ليس كذلك. ولكن الحقيقة هي أنه في كثير من الأحيان تنشأ InterruptedException بسبب وجود خطأ في التعليمات البرمجية الخاصة بك ، (مثل حلقة لا نهاية لها ، dead-lock) ، و Interrupt هي طريقة مؤشر ترابط آخر للتعامل مع هذا الخطأ.

إذا كنت تعلم أن هناك تنظيفًا عقلانيًا ، فقم بذلك. إذا كنت تعرف سببًا أعمق للمقاطعة ، يمكنك التعامل بشكل أكثر شمولية.

لذلك باختصار ، يجب أن تتبع اختياراتك للتعامل مع هذه القائمة:

  1. بشكل افتراضي ، أضف إلى الرميات.
  2. إذا لم يُسمح بالإضافة إلى الرميات ، فقم برمي RuntimeException (e). (أفضل خيار من الخيارات السيئة متعددة)
  3. فقط عندما تعرف سببًا صريحًا للمقاطعة ، تعامل مع ما تريد. إذا كانت معالجة الخاص بك محلية إلى طريقتك ، ثم إعادة تعيين مقاطعة من قبل استدعاء Thread.currentThread (). المقاطعة ().
8
nedruod

أردت فقط إضافة خيار أخير إلى ما ذكره معظم الناس والمقالات. كما ذكر mR_fr0g ، من المهم التعامل مع المقاطعة بشكل صحيح إما عن طريق:

  • نشر InterruptException

  • استعادة حالة المقاطعة على الموضوع

أو بالإضافة إلى ذلك:

  • معالجة مخصصة للمقاطعة

لا حرج في التعامل مع المقاطعة بطريقة مخصصة تبعا لظروفك. نظرًا لأن المقاطعة هي طلب إنهاء ، على عكس أمر قوي ، فمن الصحيح تمامًا إكمال العمل الإضافي للسماح للتطبيق بمعالجة الطلب بأمان. على سبيل المثال ، إذا كان مؤشر الترابط سائلاً ، فانتظر IO أو استجابة الأجهزة ، عندما يتلقى المقاطعة ، يكون من الصحيح تمامًا إغلاق أي اتصالات قبل تشغيل سلسلة الرسائل بأمان.

أوصي بشدة بفهم الموضوع ، لكن هذا المقال مصدر جيد للمعلومات: http://www.ibm.com/developerworks/Java/library/j-jtp05236/

2
TheIT

أود أن أقول في بعض الحالات ، لا بأس في عدم القيام بأي شيء. من المحتمل ألا يكون هناك شيء يجب عليك فعله افتراضيًا ، ولكن في حالة عدم وجود طريقة للمقاطعة ، لست متأكدًا مما يجب فعله (ربما خطأ في التسجيل ، لكن هذا لا يؤثر على تدفق البرنامج).

حالة واحدة ستكون في حالة وجود قائمة انتظار (حظر) مهمة. في حال كان لديك خيط خفي يعالج هذه المهام ولا تقاطع الخيط بنفسك (على حد علمي فإن jvm لا يقاطع خيط الخفي في إغلاق jvm) ، لا أرى أي طريقة لحدوث المقاطعة ، وبالتالي قد يكون ذلك تجاهل فقط. (أعلم أن خيطًا خفيًا قد يتم قتله على يد jvm في أي وقت وبالتالي فهو غير مناسب في بعض الحالات).

تحرير: حالة أخرى قد تكون حراسة الكتل ، على الأقل على أساس تعليمي أوراكل في: http://docs.Oracle.com/javase/tutorial/essential/concurrency/guardmeth.html

0
Bjarne Boström