我首先定义 ProgressMonitor:
progressMonitor = new ProgressMonitor(parent, "Starting processing ...", "", 0, maxNumberProcesses+1);
progressMonitor.setProgress(0);
并在同一线程上使用 ExecutorService 和 invokeAll() 来处理 Callables 列表:
ExecutorService execService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); // use all available processors at startup
execService.invokeAll(callables); // wait for all tasks to complete
execService.shutdownNow(); // free thread pool resources
每个 Callable 的形式为:
class Callable implements Callable<List<String>>
{
public List<String> call()
{
List<String> files = doSomeStuff();
progressBarUpdate();
return files;
}
}
IE; 每个 Callable 调用 progressBarUpdate():
private void progressBarUpdate()
{
if (progressMonitor != null)
{
Lock lock = new ReentrantLock();
lock.lock();
try
{
progressMonitor.increment();
}
finally
{
lock.unlock(); // release lock
}
}
}
每个 doSomeStuff() 都有自己的异常处理,如果发生错误或抛出异常,则返回空值。这就是为什么返回类型是 List 并且在这种情况下返回 null 的原因。Callables 和它们返回的文件列表之间没有交叉,它们都在那里维护自己的文件列表。
我发现它工作正常,但偶尔会抛出以下形式的 InterruptedException:
Disposal was interrupted:
java.lang.InterruptedException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:503)
at java.awt.EventQueue.invokeAndWait(EventQueue.java:1263)
at java.awt.Window.doDispose(Window.java:1209)
at java.awt.Dialog.doDispose(Dialog.java:1196)
at java.awt.Window.dispose(Window.java:1147)
at javax.swing.ProgressMonitor.close(ProgressMonitor.java:311)
at javax.swing.ProgressMonitor.setProgress(ProgressMonitor.java:264)
显示达到监视器最大值时 setProgress() 调用 close() :
public void setProgress(int nv) {
if (nv >= max) {
close();
}
...
并且 close() 包含许多其他非线程安全调用。
我已经修改了我的代码,因此不满足条件 nv>=max 并且我在 invokeAll() 之后显式调用 ProgressMonitor.close(),但我仍然不相信这种方法是完全线程安全的。
有没有其他人遇到过这种情况并找到了坚如磐石的解决方案?
谢谢
格雷厄姆
PS。请注意,ProgressMonitor 不是 Swing 小部件,而是封装了 Swing 组件。因此,我确保 ProgressMonitor 不在 EDT 上运行。