SwingWorker:在工作线程中创建Swing组件并在EDT中添加

时间:2015-04-11 15:52:07

标签: java multithreading swing swingworker

根据SwingWorker Javadoc:

  

使用Swing编写多线程应用程序时,请记住两个约束:

     
      
  • 不应在Event Dispatch Thread上运行耗时的任务。否则应用程序将无响应。
  •   
  • 只能在Event Dispatch Thread上访问Swing组件。
  •   

因此,在使用SwingWorker时,我们必须仅使用done()process()方法访问Swing组件。

所以,我创建了一个示例应用程序,它从数据库中以块的形式加载3000行,每个行包含50行并显示它。

SwingWorker<List<Person>, Person> worker = 
   new SwingWorker<List<Person>, Person>() {

      protected List<Person> doInBackground() {
         List<Person> data = new ArrayList<>();
         while (hasMoreData()) {
            List<Person> chunk = loadFiftyRows();
            data.addAll(chunk);
            publish(chunk);
         }
         return data;
      }

      protected void process(List<Person> chunks) {
         for (Person person : chunks) {
            container.add(createPanelFor(person));
         }
         container.revalidate();
         container.repaint();
      }

   };
worker.execute();

因为,所有转弯访问必须在EDT上完成,我正在为JPanel方法中的每个person创建新的process()个实例。但是,启动时应用程序仍然非常繁重。它在数据加载时冻结并响应事件,已经很晚了。

虽然我们一次发布50行,但在EDT上调用process()方法时,块大小会变大,有时会增加1000行。我认为这是延迟的原因,在EDT上创建了1000个JPanel实例!

我觉得,创建1000个JPanel的新实例也是一项非常繁重的任务,需要在EDT上执行。 因此,我们无法在JPanel方法中创建这些doInBackground()个实例,将其存储在集合中,然后将已创建的JPanel个实例添加到container个实例中process方法?

但是,它会与声明相矛盾,“只应在Event Dispatch Thread上访问Swing组件”!

此声明是否意味着,已添加到Swing组件层次结构中的现有Swing组件而不是新创建的Swing组件?

1 个答案:

答案 0 :(得分:0)

Swing Threading Policy州:

  

一般来说,Swing不是线程安全的。除非另有说明,否则必须在事件派发线程上访问所有Swing组件和相关类。   典型的Swing应用程序响应于从用户手势生成的事件进行处理。例如,单击JButton会通知添加到JButton的所有ActionListener。由于在事件调度线程上调度了从用户手势生成的所有事件,因此大多数开发人员不会受到限制的影响。

     

然而,影响在于构建和显示Swing应用程序。在事件派发线程上不调用对应用程序的主要方法或Applet中的方法的调用。因此,在构建并显示应用程序或小程序时,必须注意将控制权转移到事件派发线程。传递控制并开始使用Swing的首选方法是使用invokeLater。 invokeLater方法调度要在事件派发线程上处理的Runnable。

您不应该在EventDispatchThread之外创建Swing组件,因为更新组件的模型会生成更多here个事件。

加深this answer可能具有启发性。

如您对问题的评论所述&#34;分页&#34;也许是一个&#34;加载栏&#34;可以解决你的问题。