java - 以线程安全的方式使用 ExecutorService 和 ProgressMonitor

标签 java multithreading concurrency executorservice progressmonitor

我首先定义 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;
    }
}

即;每个Callable调用progressBarUpdate():

private void progressBarUpdate()
{
    if (progressMonitor != null)
    {
        Lock lock = new ReentrantLock();
        lock.lock();
        try
        {
            progressMonitor.increment();
        }
        finally
        {
            lock.unlock(); // release lock
        }
    }
}

每个 doSomeStuff() 都有自己的异常处理,如果发生错误或抛出异常,则返回 null 值。这就是为什么返回类型是 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 上运行。

最佳答案

如果您想执行后台任务并显示进度,您应该使用 SwingWorkerSwingWorker 有一个可以监听的 progress 属性。它确保进度更新在事件调度线程中完成,而任务在后台线程中完成。

例如:

SwingWorker<?,?> task = ...;
final JProgressBar progressBar = new JProgressBar(0, 100);

task.addPropertyChangeListener(
        new PropertyChangeListener() {
            public  void propertyChange(PropertyChangeEvent evt) {
                 if ("progress".equals(evt.getPropertyName())) {
                     progressBar.setValue((Integer)evt.getNewValue());
            }
        }
 });

完整的示例代码位于SwingWorker的javadoc中.

关于java - 以线程安全的方式使用 ExecutorService 和 ProgressMonitor,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20759129/

相关文章:

java - IN() 和 WHERE= 怎么做?使用 Spring 的 JDBCTemplate 进行 SQL 查询

c - C 中使用信号量的有界缓冲区

c++ - 为什么在重新执行我的多线程代码后输出不一样?

java - 在 Java 中使用并发在磁盘上创建键值存储

java - 在您开始滚动之前,回收站 View 不会更新

java - IntelliJ IDEA 2016.3.4 : Abnormal build process termination

java - Mockito、argThat 和 hasEntry

visual-studio - Visual Studio 调试器的线程问题

java - volatile ,在 x86 处理器上没有用处

java - 暗星计划是否现实?