我一直在使用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
答案 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更新来查看代码并进行实验,并查看是否可以通过这种方式阻止问题...敬请关注:)
编辑:即使完全删除这些更新,我也会抛出相同的异常......