Java - 任务和期货 - 我是否需要捕获异常,还是可以将它们留给应用程序线程?

时间:2015-07-29 15:48:32

标签: java multithreading exception concurrency javafx-8

我正在使用JavaFX编写转换程序,并使用推荐的javafx.concurrent.Task来完成远离JavaFX应用程序线程的繁重工作。我还在其中使用java.util.concurrent.Futurejava.util.concurrent.ExecutorService来完成可以同时完成的额外工作。

然而,很多工作都涉及可能抛出的方法,如果发生这种情况,我需要进程停止。我目前在所有地方发送try-catch个版块的垃圾邮件并返回错误,而不是让异常冒出来。

但由于call()Future中的Task都有throws Exception声明,以防有任何未被删除的声明,我是否可以抓住异常在期货中,当Task终止时,让它们由应用程序线程处理? 因为异常将执行我想要的操作并终止线程,同时提供有关线程停止到应用程序线程的原因的额外信息,以便我可以显示适当的警报。

我想要这样做的另一个原因是在期货中我需要访问Task线程中的值,但我不需要改变它们所以我想制作价值观final并在lambdas中创建Futures。 try-catch区块使问题变得复杂,因为我无法像我一样制作尽可能多的值final(或有效final)。这是因为我在初始化时可能会抛出可能抛出的方法的返回值。因此,我必须在try-catch中包围赋值,因此需要在将临时变量复制到final变量之前继续创建临时变量,这会使进程看起来很乱并且可能会浪费内存。

是不是在TaskFuture内捕捉异常是不是一个好主意?在应用程序线程之前是否存在任何未捕获异常的重大缺陷或问题?

以下是我目前在控制器类中处理应触发此过程的事件的示例:

ExecutorService converterExecutor = Executors.newSingleThreadExecutor();
ConverterTask converterThread = new ConverterTask()
converterExecutor.execute(converterThread);
Boolean success = null;
try
{
    success = converterThread.get();
}
catch (InterruptedException | ExecutionException e1)
{
    e1.printStackTrace();
    return false;
}
if (success == null)
{
    return false;
}

包含长期运行逻辑的ConverterTask类在另一个线程中运行

public class ConverterTask extends Task< Boolean >
{
    public Boolean call() throws Exception
    {
        //do stuff
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Future< String > skeletonThread = executor.submit(new Callable< String >()
        {
            //stuff that can throw exceptions
        });
        //do more stuff
        String temp_sklData = null;
        try
        {
            temp_sklData = skeletonThread.get();
        }
        catch (InterruptedException | ExecutionException e1)
        {
            e1.printStackTrace();
            return false;
        }
        if (temp_sklData == null)
        {
            return false;
        }
        final String sklData = temp_sklData;
        //do more stuff including use sklData in a Lambda Future
    }
}
如果我宣传异常是一个好主意,那么

以及我想在converterTask做什么

public class converterTask extends Task< Boolean >
{
    public Boolean call() throws Exception
    {
        //do stuff
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Future< String > skeletonThread = executor.submit(new Callable< String >()
        {
            //stuff that can throw exceptions
        });
        //do more stuff
        final String sklData = skeletonThread.get();
        //do more stuff including use sklData in a Lambda Future
    }
}

1 个答案:

答案 0 :(得分:0)

由于其他人在评论中指出的原因,我并不真正理解您的代码结构。但是你的问题的基本答案是你应该使用try - catch,如果你可以优雅地处理异常(这通常意味着你仍然可以返回一个有意义的结果),如果没有,就让它们传播。

因此,ConverterTask将一个String转换为另一个public class ConverterTask extends Task<String> { private final String textToConvert ; public ConverterTask(String textToConvert) { this.textToConvert = textToConvert ; } @Override public String call() throws Exception { String result = doConversion(textToConvert); // may throw exception... return result ; } } ,这可能会引发阻止转换发生的异常,看起来像

Executor conversionExec = ... ;

// ...

ConverterTask converterTask = new ConverterTask(someText);
converterTask.setOnSucceeded(e -> {
    String result = converterTask.getValue();
    // process result...
});
converterTask.setOnFailed(e -> {
    // code to execute in case of unhandled exception...
    // note you can get the exception with
    Throwable thingThatWentWrong = converterTask.getException();
    // ...
});

conversionExec.execute(converterTask);

,典型的用法是

onSucceeded

请注意,处理程序(onFailed@Override public String call() { try { String result = doConversion(textToConvert); return result ; } catch (Exception e) { // fallback computation that doesn't throw exception... String result = doSafeConversion(textToConvert); return result ; } } )中的代码都是在FX Application Thread上执行的,因此您不应该阻止这些方法,但是您可以访问UI元素。 / p>

如果您有可以恢复的例外情况,那么您可以采取行动

onFailed

然后您不需要@Override public String call() throws Exception { String partialResult ; // recoverable: try { partialResult = doSomeProcessing(textToConvert); } catch (Exception e) { partialResult = computeFallbackValue(textToConvert); } // non-recoverable: may throw exception which is propagated out String result = completeComputation(partialResult); return result ; } 处理程序。

显然,如果您有一些可恢复的异常和一些不可恢复的异常,您可以将这两种技术结合起来:

onFailed

(现在你需要再次使用Compensation处理程序。)