سؤال

أنا حاليا الصيد الخلل سيئة في مجتمع متعدد الخيوط البيئة باستخدام FutureTasks و المنفذين.الفكرة الأساسية هو أن يكون لديك عدد محدد من المواضيع تنفيذ الفردية FutureTasks أن حساب النتيجة التي سيتم عرضها في الجدول (ناهيك عن واجهة المستخدم الرسومية الجانب هنا).

لقد كنت أبحث في هذا لفترة طويلة, أنا بدأت أشك في سلامة عقلي.

تنظر هذه قطعة من التعليمات البرمجية:

public class MyTask extends FutureTask<Result> {
   private String cellId;
   ...
   protected void done() {
      if (isCancelled()) return;
      try {
          Result r = get(); // should not wait, because we are done
          ... // some processing with r
          sendMessage(cellId, r);
      } catch (ExecutionException e) { // thrown from get
         ... 
      } catch (InterruptedException e) { // thrown from get
         ... 
      }
   }
   ...
}

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

وثائق FutureTask.به() يقول:

محمية طريقة الاحتجاج عند هذه المهمة الانتقال إلى الدولة isDone (سواء بشكل طبيعي أو عن طريق الإلغاء).تطبيق الافتراضي لا يفعل شيئا.فرعية قد تجاوز هذا الأسلوب في الاحتجاج الانتهاء رد أو إجراء مسك الدفاتر.لاحظ أنه يمكنك الاستعلام عن الوضع في الداخل تنفيذ هذا الأسلوب لتحديد ما إذا كانت هذه المهمة قد تم إلغاؤها.(API المرجعية)

ولكن ما لا تحصل عليه من وثائق FutureTask هي دلالات في حين done() يتم تنفيذ.ما إذا كنت تمر isCancelled() الاختيار في البداية, ولكن بعد ذلك بعض الصفحات الأخرى تتصل بي cancel() الطريقة ؟ من شأنها أن تتسبب في مهمتي أن تغير رأيها و الرد isCancelled() == true من ثم ؟

إذا كان الأمر كذلك, كيف تعرف في وقت لاحق إذا تم إرسال الرسالة?تبحث في isDone() فقط أخبرني أن تنفيذ المهمة انتهت ، ولكن كما isCancelled() صحيحا ثم كذلك, أنا لا يمكن أن أعرف ما إذا كان يجب إرسال الرسالة في الوقت المناسب.

ربما كان هذا واضحا, ولكن أنا حقا لا أرى ذلك الآن.

هل كانت مفيدة؟

المحلول

من API (التشديد من الألغام):

الجمهور منطقية إلغاء(منطقية mayInterruptIfRunning)

وصف نسخ من واجهة:المستقبل

محاولات إلغاء تنفيذ هذه المهمة. هذه المحاولة ستفشل إذا كانت المهمة قد أنجزت بالفعل, بالفعل تم إلغاء أو لا يمكن إلغاؤها لأي سبب آخر.

حتى FutureTask تعمل خارج افتراض أنه لا يمكنك إلغاء مهمة عندما انتقلت إلى isDone المرحلة.

نصائح أخرى

FutureTask#done() ويسمى هناك أكثر من مرة لأي سبيل المثال ، ومن يسمى فقط لسبب واحد run() أكملت إما مع أو بدون خطأ ، أو cancel() ركض قبل أي من الأحداث السابقة التي حدثت.سجل إنجاز أي من هذه النتائج هو الإغلاق.والسبب FutureTask الانتهاء لا يمكن تغيير بغض النظر عن الأحداث المنافسة على ما يبدو يحدث "في نفس الوقت."

ومن ثم في FutureTask#done() واحد فقط من isCancelled() أو isDone() سيعود صحيح ثم إلى الأبد.إنه من الصعب التمييز بين isDone() التقارير الحقيقية عن طريق الخطأ أو الانتهاء بنجاح.لا يمكنك تجاوز set() أو setException(Throwable) بشكل حاسم ، سواء مندوب الداخلية AQS أن تقرر ما إذا كان محاولة لتسجيل ناجحة العائد من القيمة أو مواجهة استثناء يجب أن العصا.تجاوز إما الطريقة الوحيدة التي تمكنك من معرفة أن كان يطلق عليه, ولكن لا يمكنك أن نلاحظ القرار الذي اتخذه قاعدة التنفيذ.إذا إما أن يحدث الحدث "متأخرا جدا" -- يقول ، بعد إلغاء—محاولة لتسجيل قيمة أو استثناء سيتم تجاهلها.

دراسة تنفيذ الطريق الوحيد أرى أن نستشف عدم إلغاء نتائج ناجحة من خطأ لدغة الرصاصة و الاتصال get().

لماذا لا ترسل رسالة "خارج" من المهمة ، استنادا إلى نتائج المستقبل<V> كائن عاد قبل ExecutorService?لقد استعملت هذا النمط يبدو للعمل بشكل جيد:تقديم مجموعة من للاستدعاء<V> المهام من خلال ExecutorService.ثم لكل الأولية المهمة ، تقديم الثانوية المهمة التي ينتظر على المستقبل<V> من المهمة الرئيسية يفعل بعض إجراءات المتابعة (مثل إرسال رسالة) إلا إذا كان المستقبل<V> يشير إلى أن المهمة الأساسية بنجاح.لا يوجد التخمين مع هذا النهج.عندما الدعوة إلى المستقبل<V>.الحصول على() العودة, كنت يضمن لك أن المهمة قد وصلت إلى المحطة الدولة ، طالما أنك لا تستدعي إصدار الحصول على أن يأخذ مهلة الحجة.

إذا كنت تأخذ هذا النهج, يجب عليك استخدام منفصلين ExecutorService الحالات:أحد المهام الرئيسية واحدة الثانوية منها.هذا هو لمنع المآزق.كنت لا تريد الثانوية المهام لبدء ويحتمل أن تكون كتلة المهام الأساسية من البداية عندما تجمع مؤشرات الترابط حجم محدود.

ليس هناك حاجة إلى تمديد FutureTask<V> في كل.فقط تنفيذ المهام الخاصة بك كما للاستدعاء<V> الكائنات.ولكن إذا كان لسبب ما كنت تريد أن يكشف إذا كانت المهمة ألغيت من داخل للاستدعاء<V> مدونة, مجرد التحقق من حالة المقاطعة الموضوع مع الخيط.توقف().

أقترح أن يكتب اختبار صغير الذي يسمح لك استدعاء cancel() في حين الخاص بك Future سبيل المثال معلقة في done() ونرى ما سيحدث.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top