سؤال

قل أن لدي التعليمات البرمجية التالية:

ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(myRunnable);

الآن، إذا myRunnable يلقي أ RuntimeExcpetion, ، كيف يمكنني التقاطه؟ طريقة واحدة ستكون لتزويد بلدي ThreadFactory التنفيذ إلى newSingleThreadExecutor() وتعيين مخصص uncaughtExceptionHandlerS ل Threadيخرج منه. هناك طريقة أخرى هي التفاف myRunnable إلى محلي (مجهول) Runnable يحتوي على تجربة القبض على المحاولة. ربما هناك حلول أخرى مماثلة أيضا. ولكن ... بطريقة ما يشعر هذا القذرة، أشعر أنه لا ينبغي أن يكون هذا معقدا. هل هناك حل نظيف؟

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

المحلول

الحل النظيف هو استخدام ExecutorService.submit() بدلا من execute(). وبعد هذا يعود لك Future ما يمكنك استخدامه لاسترداد النتيجة أو استثناء المهمة:

ExecutorService executor = Executors.newSingleThreadExecutor();
Runnable task = new Runnable() {
  public void run() {
    throw new RuntimeException("foo");
  }
};

Future<?> future = executor.submit(task);
try {
  future.get();
} catch (ExecutionException e) {
  Exception rootException = e.getCause();
}

نصائح أخرى

تزيين Runnable في Runnable آخر يمسك باستثناءات وقت التشغيل ومعالجتها:

public class REHandler implements Runnable {
    Runnable delegate;
    public REHandler (Runnable delegate) {
        this.delegate = delegate;
    }
    public void run () {
        try {
            delegate.run ();
        } catch (RuntimeException e) {
            ... your fancy error handling here ...
        }
    }
}

executor.execute(new REHandler (myRunnable));

لماذا لا تتصل ExecutorService#submit(), ، احصل على ال Future ثم قم بتعامل مع استثناءات محتملة بنفسك عند الاتصال Future#get() ?

Skaffman صحيحة في ذلك باستخدام submit هو أنظف النهج. نهج بديل هو الفئة الفرعية ThreadPoolExecutor وتجاوز afterExecute(Runnable, Throwable). وبعد إذا اتبعت هذا النهج تأكد من الاتصال execute(Runnable) بدلا من submit(Runnable) أو afterExecute لن يتم استدعاء.

لكل وصف API:

تم استدعاء الأسلوب عند الانتهاء من تنفيذ Runnable المعطى. يتم استدعاء هذه الطريقة بواسطة مؤشر الترابط الذي أعدم المهمة. إذا لم تكن غير فارغة، فإن الرمي هو غير قديم RuntimeException أو Error تسبب هذا التنفيذ لإنهاء فجأة.

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

مهمة(Callable أو Runnable) ارسلت الى ThreadPoolExecutors سيتم تحويل إلى FuturnTask, ، يحتوي على الدعامة المسماة callable يساوي المهمة التي تقدمها. futurntask لها خاص بها run الطريقة كما يلي. كل الاستثناء أو رمي رمي في c.call() سيتم اصطيادها ووضعها في الدعامة المسماة outcome. وبعد عند الاتصال FuturnTask get طريقة، outcome سيتم رميها

futurntask.run من رمز المصدر JDK1.8

public void run() {
        ...
        try {
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    // save ex into `outcome` prop
                    setException(ex);
                }
                if (ran)
                    set(result);
            }
        }
        ...
    }

إذا كنت تريد التقاط الاستثناء:

      1. إجابة Skaffman
      2. الكتابة فوق `afterexecute` عندما كنت جديد threadpoolexecutor
        @Override
        protected void afterExecute(Runnable r, Throwable t) {
            super.afterExecute(r, t);
            Throwable cause = null;
            if (t == null && r instanceof Future) {
                try {
                    ((Future<?>) r).get();
                } catch (InterruptedException | ExecutionException e) {
                    cause = e;
                }
            } else if (t != null) {
                cause = t;
            }
            if (cause != null) {
                // log error
            }
        }
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top