سؤال

لقد أرسلت مهمة باستخدام المنفذين وأريد أن تتوقف بعد مرور بعض الوقت (على سبيل المثال.5 دقائق).لقد حاولت أن أفعل مثل هذا:

   for (Future<?> fut : e.invokeAll(tasks, 300, TimeUnit.SECONDS)) {
         try {
             fut.get(); 
         } catch (CancellationException ex) {
             fut.cancel(true);   
             tasks.clear();
         } catch(ExecutionException ex){
             ex.printStackTrace(); //FIXME: gestita con printstack       
         }
   }

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

Exception in thread "Thread-1" java.util.ConcurrentModificationException

هل هناك شيء خاطيء؟كيف يمكنني إيقاف المهام المقدمة والتي لا تزال تعمل بعد 5 دقائق؟

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

المحلول

فقط لأنك اتصلت cancel() على Future لا يعني أن المهمة ستتوقف تلقائيًا.عليك القيام ببعض الأعمال ضمن المهمة للتأكد من أنها ستتوقف:

  • يستخدم cancel(true) بحيث يتم إرسال المقاطعة إلى المهمة.
  • مقبض InterruptedException.إذا قامت إحدى الوظائف في مهمتك بطرح ملف InterruptedException, ، تأكد من الخروج بأمان في أسرع وقت ممكن عند اكتشاف الاستثناء.
  • تحقق بشكل دوري Thread.currentThread().isInterrupted() إذا كانت المهمة لا حساب مستمر.

على سبيل المثال:

class LongTask implements Callable<Double> {
    public Double call() {

         // Sleep for a while; handle InterruptedException appropriately
         try {
             Thread.sleep(10000);
         } catch (InterruptedException ex) {
             System.out.println("Exiting gracefully!");
             return null;
         }


         // Compute for a while; check Thread.isInterrupted() periodically
         double sum = 0.0;
         for (long i = 0; i < 10000000; i++) {
             sum += 10.0
             if (Thread.currentThread().isInterrupted()) {
                 System.out.println("Exiting gracefully");
                 return null;
             }
         }

         return sum;
    } 
}

وأيضاً كما ذكرت مشاركات أخرى: ConcurrentModificationException يمكن رميها حتى في حالة استخدام الخيط الآمن Vector فئة، لأن التكرارات التي تحصل عليها من Vector ليست آمنة لمؤشر الترابط، وبالتالي تحتاج إلى المزامنة.تستخدم حلقة for المتقدمة التكرارات، لذا انتبه:

final Vector<Double> vector = new Vector<Double>();
vector.add(1.0);
vector.add(2.0);

// Not thread safe!  If another thread modifies "vector" during the loop, then
// a ConcurrentModificationException will be thrown.
for (Double num : vector) {
    System.out.println(num);
}

// You can try this as a quick fix, but it might not be what you want:
synchronized (vector) {    // "vector" must be final
    for (Double num : vector) {
        System.out.println(num);
    }
}

نصائح أخرى

ووConcurrentModificationException قادم من دعوتكم الى tasks.clear() بينما Exceutors الخاص بك هو بالتكرار عبر tasks Vector الخاص بك. ما يمكنك القيام به هو محاولة لدعوة <لأ href = "http://java.sun.com/javase/6/docs/api/java/util/concurrent/ExecutorService.html#shutdownNow٪28٪29" يختلط = " نوفولو noreferrer "> shutdownNow() على ExecutorService بك

والحالة الأكثر شيوعا للConcurrentModificationException هو عندما يتم تعديل vector في نفس الوقت الذي يتم كرر ذلك. وغالبا ما يتم ذلك في موضوع واحد. تحتاج إلى عقد تأمين على Vector عن التكرار كله (والحرص على عدم الجمود).

وfut.get () هي دعوة حظر، حتى بعد المهلة، سوف تمنع حتى تنجز المهمة. إذا كنت ترغب في التوقف عن أقرب إلى علامة 5 دقائق وقت ممكن، فإنك تحتاج إلى التحقق من العلم المقاطعة، أنا فقط ننصح القيام بذلك باستخدام طريقة Thread.isInterrupted () الذي يحافظ على الدولة المقاطعة. إذا كنت تريد أن تتوقف فقط على الفور ولا تحتاج إلى تنظيف أي دولة، ثم رمي استثناء والتي سيتم القبض عليهم من قبل المستقبل، وأشارت إليك في صورة ExecutionException.

وfut.cancel (صحيح) لا تفعل أي شيء مثل invokeAll () طريقة سبق ان فعلت هذا بالنسبة لك.

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

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

ووضع fut.cancel(true); في منع أخيرا

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