SwingWorker上的异常是无法捕获的

时间:2012-01-10 21:22:58

标签: java multithreading swing exception-handling swingworker

我一直在使用Java线程,以便为管道中的流程提供GUI平台。我已经设法解决了SwingWorker的一些问题,但这个问题似乎难以理解。

我的SwingWorker看起来像是:

SwingWorker<Boolean,Object> worker = new SwingWorker<Boolean,Object>() {
         @Override 
        public Boolean doInBackground() {
             return launchBlockingPipelineProcess(process, instance, project, logger, state);
         }

         @Override
         protected void done(){
             boolean success = false;
             try{
                 success = get();
                 if (!success){
                     state.setTaskFailed(true);
                     }
                 if (process.getStatus().equals(Status.Interrupted)){
                     state.setTaskInterrupted(true);
                     }
             }catch (Exception ex){
                state.setTaskFailed(true); 
                }

             processCompleted(process, success, state);
         }

    };

我用它来运行Java进程;启动代码的简化版本是:

try{
    Class<?> target_class = Class.forName(main_class);

    CommandInstance instance = (CommandInstance)target_class.newInstance();
    CommandFunctions.ProcessState state = instance.execute(args);

}catch (InvocationTargetException e){
    throw new PipelineException("Java process '" + this.getName() + "." + uid + "' encountered exception: " + e.getCause().getMessage());
}catch (Exception e){
    throw new PipelineException("JavaProcess encountered exception invoking target: " + e.getMessage());
    }

进程本身有一个try-catch块代码,用于从文件中加载一些数据。但是,尽管被包装在两层try-catch块中(实际上是三层,如果你计算done()方法),当加载器抛出一个Exception时,它会打印一个堆栈跟踪,没有捕获到Exception,而{ {1}}线程挂起(代码暂停,因此我不能再强制中断)。

这种异常悬挂也发生在其他情况下;最令人费解的是,在其他看似相同的情况下,异常被捕获并且线程优雅地退出。

虽然我会继续搜索,但我还没能在网上找到很多相关信息。我不是Swing线程的专家,所以我希望有人可能对这类问题有所了解。我喜欢这是一个非常愚蠢的错误:)

编辑:@Adrian,这是堆栈跟踪。它似乎停了一半......非常奇怪:

SwingWorker

EDIT2:在Eclipse中进行调试,我可以在它被抛出的那一行的断点处停下来(好吧,前一步);此时的堆栈跟踪是:

java.io.EOFException
    at java.io.RandomAccessFile.readFully(RandomAccessFile.java:399)
    at mgui.io.standard.nifti.Nifti1Dataset.readVolBlob(Nifti1Dataset.java:2179)
    at mgui.io.standard.nifti.Nifti1Dataset.readDoubleVol(Nifti1Dataset.java:1916)
    at mgui.io.standard.nifti.NiftiVolumeLoader.setGrid3DBlocking(NiftiVolumeLoader.java:186)
    at mgui.io.domestic.shapes.VolumeFileLoader.setGrid3D(VolumeFileLoader.java:237)
    at mgui.io.domestic.shapes.VolumeFileLoader.getGrid3D(VolumeFileLoader.java:139)
    at mgui.io.domestic.shapes.VolumeFileLoader.getGrid3D(VolumeFileLoader.java:97)
    at minc.MincFunctions.create_volume_atlas_masks(MincFunctions.java:5240)
    at minc.MincFunctions.run_command(MincFunctions.java:153)
    at mgui.command.CommandInstance.execute(CommandInstance.java:87)
    at mgui.pipelines.JavaProcess.run(JavaProcess.java:141)
    at mgui.pipelines.PipelineFunctions.launchBlockingPipelineProcess(PipelineFunctions.java:238)
    at mgui.pipelines.PipelineFunctions.launchPipelineProcess(PipelineFunctions.ja

3 个答案:

答案 0 :(得分:2)

是的,可以从Exception(s)的方法SwingWorker中获取done(),但需要严格命名每个帖子,在此thread中更多,尤其是answer by @trashgod,而且我还没有找到另一种可能性,以另一种方式

答案 1 :(得分:0)

我解决了类似的表问题,因为在AWT线程绘制UI时没有干扰。 我使用invokeLater()将我的线程与UI线程同步。

有关详细信息,请参阅EventQueue

答案 2 :(得分:0)

@Adrian,感谢您的建议;我不认为我直接从SwingWorker线程进行任何UI更新;我确实对JTree节点进行了更新以指示进程的成功或失败,但我使用发布/进程机制来确保从EDT调用所有UI更新:

这些是从执行管道调用的侦听器处理程序:

@Override
public void pipelineTaskTerminated(DynamicPipelineEvent event, PipelineTask task) {
    publish(task);
}

@Override
public void pipelineTaskUpdated(DynamicPipelineEvent event, PipelineTask task) {
    // Here we can publish the update to a task status
    publish(task);

}

以下是流程方法:

@Override
protected void process(List<PipelineTask> tasks) {

    // Update task listeners on the Event-Dispatch Thread
    for (int i = 0; i < tasks.size(); i++){
        PipelineTask task = tasks.get(i);
        InterfacePipeline pipeline = task.getPipeline();
        if (pipeline != null){
            task.fireStatusChanged();
            }
        }

}

最后,以下是JTree处理事件的方式:

public void taskStatusChanged(PipelineTaskEvent e){
    if (model == null) return;
    model.nodeStructureChanged(this);
    tree.repaint();
}

除了(可能提供信息)之外,对JTree的这种调用也不会导致UI的更新,尽管它是从EDT调用的。强制树更新的唯一方法是单击节点本身。可能是新线程的问题,但可能是相关的。

我将通过从线程中删除任何潜在的UI更新来查看代码并进行实验,并查看是否可以通过这种方式阻止问题...敬请关注:)

编辑:即使完全删除这些更新,我也会抛出相同的异常......