SwingWorker过程的设计

时间:2014-09-12 14:19:29

标签: java swing swingworker

目前我有一个像这样的SwingWorker进程的实现。请注意,这些不是实际代码。只是骷髅。

private void jButtonSomeButton ( .... ) {
    .....
    for( File file: files){                   
       worker( args1, args2 );           
    }

} 
private void worker( args1, args2 ){
   mytask = new SwingWorker<Object, Object>(){ 
      public Object doInBackground(){
          while( !isCancelled() ){
               individualtask( args1, args2 );
          }
      }
     ..... 

   }
}

private void individualtask(args1, args2){
   ...
   table.addRow( somevector );  //add some data to row
   ...
}

虽然我已经完成了上述工作,但我发现有时行数据会出错。有些人物可能会丢失等等。有时他们没事。我相信我需要一些同步机制,但我没有这方面的经验。你能帮忙建议改进上面的代码吗?感谢

2 个答案:

答案 0 :(得分:5)

请注意,doInBackground()方法中的代码在Event Dispatch Thread (EDT)之外运行。然后在其中调用individualTask(args1, args2)并因此调用table.addRow(...)在概念上是错误的。更不用说JTable API中不存在addRow(...)而是DefaultTableModel。{/ p>

繁重的任务必须在doInBackground()线程中运行,并且必须在EDT中执行Swing组件更新。

正确的方法是使用publish()process()方法,如Tasks that Have Interim Results课程的Concurrency in Swing部分所述。

说过我建议你也重新考虑这一部分:

private void jButtonSomeButton ( ... ) {
    ...
    for( File file: files){                   
       worker( args1, args2 );           
    }
}

如果您触发多个更新同一个表的工作人员,那么结果也不会是预期的。当然,这完全取决于你需要达到的并行度水平。


修改

基于此评论:

  

我必须处理目录中的文件,但我不想连续进行。这就是我使用worker()的原因。你怎么建议我这样做?

在这种情况下,使用SwingWorker肯定是正确的选择。但请考虑这种情况:

假设目录中有两个文件,即文件A和B.如果触发两个不同的工作程序来处理A和B,那么将有两个并行任务更新同一个表。因此,行将非常异步地添加到表中,您可以从文件A解析行0,1,2,4,7,从文件B解析行3,5,6,8。如果订单在哪些行上被添加到表中,最重要的是解析这些文件的文件并不重要,那么方法就没问题了。

另一方面,如果要首先添加从文件A解析的所有行,然后再添加从文件B解析的所有行,请考虑将此for (File file : files)循环放在doInBackground()内。这将确保文件处理和表更新之间的并行性,但要遵守文件处理的顺序。例如:

SwingWorker<Void, Vector> worker = new SwingWorker<Void, Vector>() {
    @Override
    protected Void doInBackground() {
        int numberOfFiles = files.size(); // or files.length if it's an array
        int processed = 0;
        for (File file : files) {
            ...
            // process each file here and then publish interim results
            publish(vector);
            ...
            int progress = (int)(++processed * 100 / numberOfFiles);
            setProgress(progress);
        }
        return null;
    }

    @Override
    protected void process(List<Vector> rows) {
        DefaultTableModel model = (DefaultTableModel)table.getModel();
        for (Vector row: rows) {
            model.addRow(row);
        }
     }
};

答案 1 :(得分:4)

您不应该从table.addRow()致电individualTask

您可以在doInBackground中执行后台任务,然后在publish中执行结果。

请参阅:

http://docs.oracle.com/javase/8/docs/api/javax/swing/SwingWorker.html