Исключение на SwingWorker не ловится - PullRequest
3 голосов
/ 11 января 2012

Я работал с потоками Java, чтобы предоставить платформу графического интерфейса для запуска процессов в конвейере.Мне удалось решить ряд проблем с 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()), когда загрузчик выдает исключение, он печатает трассировку стека, исключение не перехватывается, а SwingWorkerзависание потока (код останавливается, поэтому я больше не могу форсировать прерывание).

Подобное зависание исключений происходило и в других обстоятельствах;Самое удивительное, что в других, казалось бы, идентичных случаях Исключение обнаруживается и поток завершается изящно.

Мне не удалось найти много об этом в Интернете, хотя я продолжу поиск.Я не являюсь экспертом в потоках Swing, поэтому я надеялся, что у кого-то есть понимание этой проблемы.Я хотел бы, чтобы это было очень глупой ошибкой с моей стороны:)

РЕДАКТИРОВАТЬ: @Adrian, вот трассировка стека.Кажется, что он застопорился на полпути ... очень странно:

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

EDIT2: отладка в Eclipse, я могу остановиться на точке останова на той строке, куда он был брошен (ну, на шаг раньше);трассировка стека в этой точке:

Nifti1Dataset.readVolBlob(short) line: 2179 
Nifti1Dataset.readDoubleVol(short) line: 1916   
NiftiVolumeLoader.setGrid3DBlocking(Grid3D, int, ProgressUpdater) line: 186 
NiftiVolumeLoader(VolumeFileLoader).setGrid3D(Grid3D, int, ProgressUpdater) line: 237   
NiftiVolumeLoader(VolumeFileLoader).getGrid3D(VolumeInputOptions, int, ProgressUpdater) line: 139   
NiftiVolumeLoader(VolumeFileLoader).getGrid3D(int) line: 97 
MincFunctions.create_volume_atlas_masks() line: 5278    
MincFunctions.run_command(String) line: 153 
MincFunctions(CommandInstance).execute(String[]) line: 87   
JavaProcess.run(String[], long) line: 141   
PipelineFunctions.launchBlockingPipelineProcess(PipelineProcessInstance, String, InterfaceProject, String, PipelineState) line: 238 
PipelineFunctions.launchPipelineProcess(PipelineProcessInstance, String, InterfaceProject, String, boolean, PipelineState) line: 78 
PipelineFunctions.launchPipelineProcess(PipelineProcessInstance, boolean, PipelineState) line: 52   
PipelineProcessInstance.launch(boolean) line: 187   
InterfacePipeline.launch(boolean) line: 388 
PipelineLauncher.doInBackground() line: 57  
PipelineLauncher.doInBackground() line: 1   
SwingWorker$1.call() line: 277  
FutureTask$Sync.innerRun() line: 303    
SwingWorker$2(FutureTask<V>).run() line: 138    
PipelineLauncher(SwingWorker<T,V>).run() line: 316  
ThreadPoolExecutor$Worker.runTask(Runnable) line: 886   
ThreadPoolExecutor$Worker.run() line: 908   
Thread.run() line: 662  

Ответы [ 3 ]

2 голосов
/ 11 января 2012

да возможно взять Exception(s) из SwingWorker методов done(), но необходимо строго назвать каждую нить, подробнее в этом нить , особенно ответ @ trashgod и я не нашел другой возможности, как это сделать по-другому

0 голосов
/ 13 января 2012

@ Адриан, спасибо за предложение;Я не думаю, что я делаю какие-либо обновления пользовательского интерфейса непосредственно из потока SwingWorker;Я делаю обновления для JTree узлов, чтобы указать на успех или неудачу процесса, но я использую для этого механизм публикации / процесса, который должен гарантировать, что все обновления пользовательского интерфейса вызываются из EDT:

Этиэто обработчики слушателей, вызываемые из выполняющегося конвейера:

@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 также не приводит к обновлению пользовательского интерфейса, несмотря на то, что он вызывается из EDT.Единственный способ принудительно обновить дерево - щелкнуть сам узел.Возможно, это проблема для нового потока, но она может быть связана.

Я рассмотрю код и поэкспериментирую, удалив ЛЮБОЕ потенциальное обновление пользовательского интерфейса из потока, и посмотрю, можно ли таким образом предотвратить проблему... следите за обновлениями:)

РЕДАКТИРОВАТЬ: Даже удаляя эти обновления в целом, я получаю одно и то же исключение ...

0 голосов
/ 11 января 2012

Я решил похожую проблему с таблицей, не вмешиваясь, когда поток AWT рисовал пользовательский интерфейс.Я использовал invokeLater() для синхронизации моего потока с потоком пользовательского интерфейса.

Подробнее см. EventQueue .

...