نقل التعليمات البرمجية من استخدام أجهزة ضبط الوقت إلى خدمة المنفذ المجدولة

StackOverflow https://stackoverflow.com/questions/637110

  •  10-07-2019
  •  | 
  •  

سؤال

أحاول نقل الرمز من استخدام Java توقيت لاستخدام scheduleexecutorservice

لدي حالة الاستخدام التالية

class A {

    public boolean execute() {
         try {
              Timer t = new Timer();
              t.schedule (new ATimerTask(), period, delay);
         } catch (Exception e) {
              return false;
         }
    }

}


class B {

    public boolean execute() {
         try {
              Timer t = new Timer();
              t.schedule (new BTimerTask(), period, delay);
         } catch (Exception e) {
              return false;
         }
    }

}

هل يجب عليّ فقط استبدال مثيلات Timer في الفئة A والفئة B بـScheduledExecutorService وتحويل فئة ATimerTask وBTimerTask إلى فئة Runnable، على سبيل المثال

class B {

    public boolean execute() {
         try {
              final ScheduledExecutorService scheduler = 
   Executors.newScheduledThreadPool(1);

              scheduler.scheduleWithFixedDelay (new BRunnnableTask(), period, delay);
         } catch (Exception e) {
              return false;
         }
    }

}

هل هذا صحيح.

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

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

المحلول

ملحوظة:الطريقة التي فعلت بها هذا سوف تسرب المواضيع!

إذا صفك B سيتم الاحتفاظ بها حول و كل حالة سيتم إغلاقه أو إغلاقه أو تحريره في النهاية، سأفعل ذلك على النحو التالي:

class B {
  final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

  public boolean execute() {
    try {
      scheduler.scheduleWithFixedDelay(new BRunnnableTask(), period, delay);
      return true;
    } catch (Exception e) {
      return false;
    }
  }

  public void close() {
    scheduler.shutdownNow();
  }
}

إذا لم تقم بهذا النوع من التنظيف في كل حالة، فسأقوم بذلك بدلاً من ذلك:

class B {
  static final ScheduledExecutorService SCHEDULER = Executors.newCachedThreadPool();

  public boolean execute() {
    try {
      SCHEDULER.scheduleWithFixedDelay(new BRunnnableTask(), period, delay);
      return true;
    } catch (Exception e) {
      return false;
    }
  }
}

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

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

نصائح أخرى

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

لا يوجد حاليا أي وسيلة جيدة للتعامل مع تكرار المهام في إطار المنفذين.

وانها حقا ليست مصممة مع هذه الحالة الاستخدام في الاعتبار، وليس هناك طريقة واقعية لتجنب ابتلاع الاستثناءات.

إذا كنت حقا يجب استخدامه لتكرار المهام، يجب على كل جدولة ننظر بشيء من هذا القبيل:

scheduler.scheduleWithFixedDelay(new Runnable() {
  public void run() {
     try {
       .. your normal code here...
     } catch (Throwable t) {
       // handle exceptions there
     }
  }
}, period, delay);
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top