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()
方法),当加载器抛出异常时,它会打印堆栈跟踪,但异常不是捕获,并且 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
I have been working with Java threads in order to provide a GUI platform for running processes in a pipeline. I've managed to work through a number of issues with SwingWorker
, but this one is seemingly incomprehensible.
My SwingWorker
looks like:
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);
}
};
I use this to run a Java process; a simplified version of the launching code is:
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());
}
The process itself has a try-catch block around code which loads some data from a file. However, despite being wrapped in two layers of try-catch blocks (actually three, if you count the done()
method), when the loader throws an Exception it prints a stack trace, the Exception is not caught, and the SwingWorker
thread hangs (the code halts so I can no longer force an interrupt).
This sort of Exception hanging has occurred in other circumstances as well; most puzzlingly, in other -- seemingly identical -- cases the Exception is caught and the thread exits gracefully.
I haven't been able to find much about this online, although I'll continue to search. I am no expert in Swing threading, so I was hoping someone might have an insight about this sort of issue. I'd love it to be a very stupid error on my part :)
EDIT: @Adrian, here is the stack trace. It seems to stall half way... very strange:
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: Debugging in Eclipse, I can halt at a breakpoint on the line where it is thrown (well, one step before); the stack trace at that point is:
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
是的,可以从
SwingWorker
的方法done()
中获取Exception(s)
,但需要严格命名每个线程,更多信息请参见 线程,尤其是@trashgod 的回答,我还没有找到另一种可能性yes is possible take
Exception(s)
fromSwingWorker
's methodsdone()
, but required strictly naming every thread, more in this thread, especially answer by @trashgod, and I haven't found another possibility of how to it another way我通过在 AWT 线程绘制 UI 时不进行干扰来解决类似的表问题。
我使用
invokeLater()
将我的线程与 UI 线程同步。有关更多详细信息,请参阅 EventQueue。
I solved a similar table problem by not interfering when the AWT thread was painting the UI.
I used
invokeLater()
to synchronize my thread with the UI thread.See EventQueue for more details.
@Adrian,感谢您的建议;我不认为我直接从
SwingWorker
线程进行任何 UI 更新;我确实对 JTree 节点进行更新以指示流程的成功或失败,但我为此使用发布/流程机制,这应确保从 EDT 调用所有 UI 更新:这些是从执行管道调用的侦听器处理程序:
这是处理方法:
最后,这是 JTree 处理事件的方式:
除了(可能提供信息)之外,对
JTree< 的调用/code> 也不会导致更新UI,尽管它是从 EDT 调用的。强制树更新的唯一方法是单击节点本身。可能是新线程的问题,但可能是相关的。
我将通过从线程中消除任何潜在的 UI 更新来检查代码并进行实验,看看是否可以通过这种方式防止问题......敬请关注:)
编辑:即使完全删除这些更新,我也会抛出相同的异常。 ..
@Adrian, thanks for the suggestion; I do not think I am making any UI updates directly from the
SwingWorker
thread; I do make updates toJTree
nodes to indicate the success or failure of a process, but I use the publish/process mechanism for this, which should ensure that all UI updates are called from the EDT:These are listener handlers called from the executing pipeline:
And here is the process method:
Finally, here is how the
JTree
handles the event:As a (potentially informative) aside, this call to the
JTree
also does not result in an update of the UI, despite its being called from the EDT. The only way to force the tree to update is by clicking on the node itself. Possibly an issue for a new thread, but it may be related.I'll go through the code and experiment by eliminating ANY potential UI updates from the thread, and see if the problem can be prevented that way... stay tuned :)
EDIT: Even removing these updates altogether I get the same Exception thrown...