Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 以线程安全的方式使用ExecutorService和ProgressMonitor_Java_Multithreading_Concurrency_Executorservice_Progressmonitor - Fatal编程技术网

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

Java 以线程安全的方式使用ExecutorService和ProgressMonitor,java,multithreading,concurrency,executorservice,progressmonitor,Java,Multithreading,Concurrency,Executorservice,Progressmonitor,我首先定义ProgressMonitor: progressMonitor = new ProgressMonitor(parent, "Starting processing ...", "", 0, maxNumberProcesses+1); progressMonitor.setProgress(0); 在同一线程上,使用ExecutorService和invokeAll()处理可调用项列表: ExecutorService execService = Executors.newFix

我首先定义ProgressMonitor:

progressMonitor = new ProgressMonitor(parent, "Starting processing ...", "", 0, maxNumberProcesses+1);
progressMonitor.setProgress(0);
在同一线程上,使用ExecutorService和invokeAll()处理可调用项列表:

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
每个可调用项的形式如下:

class Callable implements Callable<List<String>>
{
    public List<String> call()
    {
        List<String> files = doSomeStuff();
        progressBarUpdate();
        return files;
    }
}
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)
每个doSomeStuff()都有自己的异常处理,如果发生错误或引发异常,则返回空值。这就是为什么返回类型是一个列表,在这种情况下返回null。可调用项和它们返回的文件列表之间没有交叉,它们都维护自己的文件列表

我发现它工作得很好,但偶尔会抛出以下形式的InterruptedException:

class Callable implements Callable<List<String>>
{
    public List<String> call()
    {
        List<String> files = doSomeStuff();
        progressBarUpdate();
        return files;
    }
}
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(),但我仍然不相信这种方法是完全线程安全的

还有其他人遇到过这种情况并找到了坚如磐石的解决方案吗

谢谢

格雷厄姆


注意ProgressMonitor不是swing小部件,而是封装swing组件。因此,我确保ProgressMonitor不会在EDT上运行。

如果要执行后台任务并显示进度,则应使用。
SwingWorker
有一个可以监听的
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任务=。。。;
最终JProgressBar progressBar=新的JProgressBar(0,100);
task.addPropertyChangeListener(
新属性ChangeListener(){
公共作废属性更改(属性更改事件evt){
if(“progress”.equals(evt.getPropertyName())){
progressBar.setValue((整数)evt.getNewValue());
}
}
});

完整的示例代码在的javadoc中。

看起来这就是导致
中断的原因:

Worker Thread (Callable1):
close() -> doDispose() -> EventQueue.invokeAndWait() {
synchronized (lock) {
            Toolkit.getEventQueue().postEvent(event);
            lock.wait(); // --> (2) blocked window disposal event gets interrupted
        }
}

ExecutorService.shutdownNow() :
 try {
                for (Worker w : workers) {
                    w.interruptNow(); // (1) --> Setting interrupt flag
                }
            } catch (SecurityException se) { // Try to back out
                runState = state;
                // tryTerminate() here would be a no-op
                throw se;
            }
从功能上看,当进度监视器完成(或达到
max
)时,在调度事件之前(可能发生,也可能不发生,这取决于事件Q的繁忙程度),服务会自动关闭

从概念上讲,我看不到代码中存在任何具体问题,但主要是执行器服务与
AWT.EventQueue
之间的隐式线程通信


您可以在
progressMonitor.increment()周围使用
InterruptedException
或在调用
Shutdownow
之前使用
ExecutorService.WaitiveTermination

progressBarUpdate()属于哪个类?它是如何接收progressMonitor的?它是具有ExecutorService和Callables列表的同一类的成员。ProgressMonitor是一个字段,因为它被所有可调用项调用。感谢您的回复。我调用invokeAll(),它等待所有任务完成,可能不需要调用waitTermination()。确实,我错过了
invokeAll
调用,但这可以再次调用interrupt
future。如果出现任何错误,请取消
,然后返回。你是如何处理
Callable中的错误的。call
方法,你能更新你的问题吗?我使用的是一个Callable集合和一个ExecutorService,它不在EDT上运行。Swing ProgressMonitor同样是一个非Swing组件。