سؤال

بعد العثور على ذلك FutureTask الجري في Executors.newCachedThreadPool() على Java 1.6 (ومن Eclipse) ابتلاع الاستثناءات في Runnable.run() الطريقة ، لقد حاولت التوصل إلى طريقة للقبض عليها دون إضافة رمي/التقاط كل ما عندي Runnable التطبيقات.

تشير واجهة برمجة التطبيقات إلى أن التجاوز FutureTask.setException() يجب أن تساعد في هذا:

يسبب هذا المستقبل الإبلاغ عن ExecutionException مع قابلية الرمي المحددة كسبب ، ما لم يتم بالفعل تعيين هذا المستقبل أو تم إلغاؤه. يتم استدعاء هذه الطريقة داخليًا بواسطة طريقة التشغيل عند فشل الحساب.

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

public class RunTest {
    public static void main(String[] args) {
        MyFutureTask t = new MyFutureTask(new Runnable() {

            @Override
            public void run() {
                throw new RuntimeException("Unchecked exception");

            }
        });

        ExecutorService service = Executors.newCachedThreadPool();
        service.submit(t);
    }
}

public class MyFutureTask extends FutureTask<Object> {

    public MyFutureTask(Runnable r) {
        super(r, null);
    }

    @Override
    protected void setException(Throwable t) {
        super.setException(t);
        System.out.println("Exception: " + t);
    }
}

سؤالي الرئيسي هو: كيف يمكنني التقاط الاستثناءات التي تم إلقاؤها في مستقبلات مستقبلية؟ لماذا لا setException الحصول على الاتصال؟

أيضا أود أن أعرف لماذا Thread.UncaughtExceptionHandler لا تستخدم الآلية بواسطة FutureTask, ، هل هناك أي سبب لهذا؟

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

المحلول

setException ربما لم يتم إجراؤها من أجل تجاوزها ، ولكن يتم توفيرها للسماح لك بتعيين النتيجة إلى استثناء ، في حالة حاجة. ما تريد القيام به هو تجاوز done() الطريقة وحاول الحصول على النتيجة:

public class MyFutureTask extends FutureTask<Object> {

    public MyFutureTask(Runnable r) {
        super(r, null);
    }

    @Override
    protected void done() {
        try {
            if (!isCancelled()) get();
        } catch (ExecutionException e) {
            // Exception occurred, deal with it
            System.out.println("Exception: " + e.getCause());
        } catch (InterruptedException e) {
            // Shouldn't happen, we're invoked when computation is finished
            throw new AssertionError(e);
        }
    }
}

نصائح أخرى

هل حاولت استخدام UncaughtExceptionHandler?

  • تحتاج إلى تنفيذ UncaughtExceptionHandler واجهه المستخدم.
  • لتعيين UncaughtExceptionHandler لخيوط البلياردو ، قدم أ ThreadFactory في ال Executor.newCachedThreadPool(ThreadFactory) مكالمة.
  • يمكنك تعيين uncaughtexceptionHandler للمعلومات التي تم إنشاؤها عبر setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)

إرسال المهام مع ExecutorService.execute, ، لأن الاستثناءات فقط التي تم طرحها من المهام المقدمة مع execute اجعلها إلى معالج الاستثناء غير الموقوف. للمهام المقدمة مع ExecutorService.submit يعتبر أي استثناء تم إلقاؤه جزءًا من قيمة إرجاع المهمة. إذا انتهت المهمة التي تم تقديمها مع إرسال باستثناء ، فستكون إعادة تدويرها عند الاتصال Future.get, ، ملفوفة في ExecutionException

حل أفضل بكثير:فحص إكمال جافا فوتوريتاس

عندما تتصل futureTask.get() لاسترداد نتيجة الحساب ، سوف يلقي استثناء (ExecutionException) إذا كان الأساس Runnable/Callable ألقى استثناء.

ExecutionException.getCause() سيعود إلى استثناء أن ال Runnable/Callable يرمي.

سوف يلقي أيضا استثناء مختلف إذا كان Runnable/Callable تم الالغاء.

لقد نظرت إلى الكود المصدري لـ FutureTask ولم يتمكن من العثور على أين setException يتم استدعاؤه.
هناك innerSetException طريقة من FutureTask.Sync (فئة داخلية من FutureTask) التي يتم استدعاؤها في حالة Throwable يتم إلقاؤها بواسطة طريقة التشغيل. يتم استدعاء هذه الطريقة أيضًا setException.
لذلك فإن طبقات مثل Javadoc غير صحيحة (أو من الصعب جدًا فهمها ...).

هناك ثلاث طرق قياسية وطريقة واحدة مرتجلة. 1. استخدم uncaughtexceptionHandler ، وضبط uncaughtexceptionHandler

Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            public void uncaughtException(Thread t, Throwable ex) {..}}

*لكن القيد هو أنه يمسك بالاستثناء الذي ألقاه الخيط ولكن في حالة المهمة المستقبلية ، يتم ابتلاعه. 2. استخدام afterExecute بعد إنشاء ThreadPoolexecutor مخصص مع الخطاف الذي تم توفيره خصيصا لهذا الغرض. النظر في مدونة ThreadPoolexecutor ، عبر إرسال> تنفيذ (هناك workqueue ، workQueue.offer) ، تتم إضافة المهام إلى قائمة انتظار العمل

   final void runWorker(Worker arg0) {
  Thread arg1 = Thread.currentThread();
  Runnable arg2 = arg0.firstTask;
  ..
     while(arg2 != null || (arg2 = this.**getTask()**) != null) {
        arg0.lock();
        ..
        try {
           this.beforeExecute(arg1, arg2);
           Object arg4 = null;
           try {
              arg2.run();
           } catch (RuntimeException arg27) {
             ..
           } finally {
              this.**afterExecute**(arg2, (Throwable)arg4);
           }

  }

getTask() {..
 this.workQueue.**poll**();
..}
  1. ثم ، والثالث يستخدم Try Try Catch داخل طريقة الاتصال ولكن لا يمكنك التقاط الاستثناء في الخارج هنا.

  2. يقوم الحل البديل باستدعاء جميع أساليب الاتصال من طريقة استدعاء لـ TaskFactory ، وهو مصنع يطلق Callables.

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