簡體   English   中英

ScheduledExecutorService的多個期貨的異常處理

[英]Exception handling with multiple futures from ScheduledExecutorService

我正在使用ScheduledExecutorService,向其中添加了提交Runnable和計划Runnable(使用scheduleWithFixedDelay)。 目的是要有非常長的運行進程,因此我的所有可運行變量都沒有定義的生存期。 我基本上希望主線程僅對異常和中斷做出反應。 計划的任務很關鍵,例如生成熱信號,因此,如果有任何線程拋出運行時異常,我想記錄該異常,中止所有其他線程並關閉程序。

我應該如何處理例外情況? ScheduledExecutorService會吞下所有異常,除非我運行Future.get()。

像下面這樣循環遍歷期貨是行不通的。 如果期貨列表中的第一項未返回任何錯誤,則該錯誤將阻止該線程偵聽可能返回錯誤的其他線程。

for (Future<?> future : futures) {
    future.get();
}

一種選擇是遍歷期貨,詢問是否完成,如下所示,但我不太喜歡這種解決方案。 我需要添加線程睡眠,因此對異常的響應被延遲。

boolean allActive = true;
while (allActive) {
    for (Future<?> future : futures) {
        if (!future.isDone()) {
             allActive = false;
             break;
        }
    }
    Thread.sleep(50);
}

我還有什么其他選擇? 還是我處理問題的方式不對? 我不應該完全使用ScheduledExecutorService自己在自己的線程中實現計划嗎?

示例代碼,請嘗試將順序更改為將來的列表! 我想要您在handle2之前添加handle的行為,但是列表的順序無關緊要:

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class Test {

    private static int i = 0;

    public static void main(String[] args) throws Exception {

        ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();

        Future<?> handle = scheduler.scheduleWithFixedDelay(new Runnable() {
            public void run() {
                System.out.println("No exception!");
                if (i > 2) {
                    System.out.println("Exception!");
                    throw new RuntimeException("foo");
                }
                i++;
            }
        }, 0, 500, TimeUnit.MILLISECONDS);

        Future<?> handle2 = scheduler.scheduleWithFixedDelay(new Runnable() {
            public void run() {
                System.out.println("Running!");
            }
        }, 0, 500, TimeUnit.MILLISECONDS);


        List<Future<?>> futures = new ArrayList<>();
        futures.add(handle2);
        futures.add(handle);

        try {
            for (Future<?> future : futures) {
                future.get();
            }
        } catch (Exception e) {
            scheduler.shutdownNow();
            System.out.println(scheduler.awaitTermination(1, TimeUnit.SECONDS));
            System.out.println("Shuwdown complete");
            e.printStackTrace();
        }
    }
}

您可以使用Listener或Observer-Like模式來做到這一點:

interface IFutureListener{
    void onException( Throwable t );
}


final IFutureListener errHandler = new IFutureListener(){
     @override public void onException( Throwable t ){
          // shutdown Service here
     }
};
// ...
Future<?> handle = scheduler.scheduleWithFixedDelay(new Runnable() {
        final IFutureListener callback = errHandler;
        public void run() {
            try{
            System.out.println("No exception!");
            if (i > 2) {
                System.out.println("Exception!");
                throw new RuntimeException("foo");
            }
            i++;
            }
            catch( Exception ex ){
                callback.onException(ex);
            }
        }
    }, 0, 500, TimeUnit.MILLISECONDS);

您可能仍需要對此進行一些調整,但這是要點。

@ dimo414在評論中寫的番石榴的ListenableFuture將為您提供類似的功能。 但是,如果您不希望/不允許使用第三方,則可以使用這種方法自己實現。

感謝@efekctive:我也建議記錄異常。 除非您確切知道自己在做什么,否則幾乎絕不應該默默地吞下它們。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM