当前位置: 首页 > 知识库问答 >
问题:

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

范轶
2023-03-14
progressMonitor = new ProgressMonitor(parent, "Starting processing ...", "", 0, maxNumberProcesses+1);
progressMonitor.setProgress(0);
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;
    }
}

即;每个可调用方调用progressBarUpdate():

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

每个doSomeStuff()都有自己的异常处理,如果发生错误或抛出异常,则返回一个空值。这就是为什么返回类型是List,并且在这种情况下返回null的原因。调用项和它们返回的文件列表之间没有交叉,它们都维护自己的文件列表。

我发现它工作得很好,但偶尔会抛出窗体的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)
public void setProgress(int nv) {
    if (nv >= max) {
        close();
    }
...

我修改了代码,使条件nv>=max不满足,并且在invokeAll()之后显式调用ProgressMonitor.Close(),但我仍然不相信这样的方法是完全线程安全的。

还有谁遇到过这种情况,找到了坚如磐石的解决方案吗?

谢谢

共有1个答案

张炳
2023-03-14

如果要执行后台任务并显示进度,则应使用SwingWorker。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的javadoc中。

 类似资料:
  • 假设我有一个Executors静态工厂方法的ExecutorService实例。 如果我从某个线程提交了一个调用,其中RetVal不是线程安全的本地实例化对象,那么当我从同一个线程获得()它时,我需要担心retvals的完整性吗?人们说局部变量是线程安全的,但我不确定当您返回一个本地实例化的对象并从其他线程接收它时,它是否适用。 下面是我的定制实现,我只是为了测试。您可以忽略EType枚举。

  • 下面我分享了我的代码,我试图使用线程安全的Nashorn作为脚本引擎来评估简单的数学公式。公式将类似于“a*b/2”,其中a 我需要知道这种方法是否有助于使Nashorn线程在这个用例中安全。我在Attila的回答中读到,我们可以在线程之间共享脚本引擎对象,因为它们是线程安全的。 对于bindings和eval,因为我们正在为每次执行evaluate创建新线程,每个线程都有自己的bindings对

  • 问题内容: 我试图基于初始化按需持有人习惯用法创建一个线程安全的单例类。这是我的代码 我的期望是以线程安全的方式初始化ExecutorService,并且那里只有一个实例(静态)。 这段代码是实现了这一目标-还是需要任何更改? 问题答案: 根据SEI 指南,您的方法很好。 但是,由于我们有枚举,因此可以使用枚举的简单方法: 而且,如果您想变得真正聪明,还可以定义枚举实现的接口。因为这样您以后可以

  • 问题内容: 是否保证线程安全? 我将把来自不同线程的作业提交到同一个ThreadPoolExecutor,在交互/提交任务之前,我是否必须同步对执行者的访问? 问题答案: 的确,有问题的JDK类似乎并未明确保证线程安全的任务提交。但是,实际上,该库中的所有ExecutorService实现实际上都是以这种方式线程安全的。我认为依靠这一点是合理的。由于实现这些功能的所有代码都放置在公共领域中,因此任

  • 问题内容: 我有一个同时通过BufferedReaders和BufferedWriters读写的Socket。我不确定从单独的线程可以执行哪些操作。我想从两个不同的线程同时写入套接字是一个坏主意。与同时从两个不同的线程中读取套接字相同。在一个线程上阅读而在另一个线程上写作又如何呢? 我问是因为我想让一个线程长时间阻塞读取,因为它等待更多数据,但是在此等待期间,我偶尔还会在套接字上发送数据。我不清楚

  • 我们的许多代码是遗留的,但我们正在向“大数据”后端移动,我试图传播更新的API调用,鼓励使用最新的Spring库等。我们的问题之一是应用程序层ID生成。出于我不明白的原因,一个更高的权威想要序列的biginteger。我本可以在失败的插入中使用重新生成和重新尝试使它们随机,但我确实被否决了。 附言。我仍然认为我的随机生成的想法比处理所有这些线程的东西要好。大整数是一个大得离谱的数字,两次生成相同的