2011-09-08 107 views
6

我正在编写一个应用程序,它使用SwingWorker执行其文件菜单操作。每个调用的方法返回一个值boolean,该值告诉操作是否成功执行。如何读取SwingWorker的结果*而无需等待?

目前我使用的繁忙等待结果,这样的:

public boolean executeOperation() { 
    final SwingWorker<Boolean, Void> worker = new SwingWorker<Boolean, Void>() { 
     @Override 
     protected Boolean doInBackground() throws Exception { 
      // .. 

      if (aborted) { 
       return false; 
      } 

      // .. 

      return true; 
     } 
    }; 

    worker.execute(); 

    // busy wait 
    while (!worker.isDone()) 
     ; 

    try { 
     return worker.get().booleanValue(); 
    } catch (Exception e) { 
     // handle exceptions .. 
     return false; 
    } 
} 

是否有解决这个的少轮询激烈的方式?

使用worker.get()直接是行不通的,因为它会阻止EDT,等待完成的任务 - 这意味着即使我从SwingWorker中打开对话框不会得到画。

编辑:如果可能,我想避免该方法(或工作人员)异步沟通其结果。我正在执行几个相互依赖的简短方法(文件 - >打开,新建,关闭,保存,另存为,退出)(即当试图退出,退出调用close,close可能调用save,save可能调用save如)。异步解决似乎会使代码变得更加复杂。

+0

您可以随时在循环中放入Thread.sleep(100)。 –

+2

这并不会改变您对结果进行轮询的事实,而不是让对象进行计算来告诉您何时完成。 – mcfinnigan

回答

6

SwingWorker的要点恰恰是在后台启动一些任务,并且不会阻止EDT。无论你想要什么东西都是同步的,无论你尝试什么,EDT都会被阻塞,或者你想要异步的东西,后台任务应该使用SwingWorker的publish方法更新其状态。

您可以在任务运行时显示阻塞模态对话框和进度条,并在任务完成后隐藏它。

另一种方法是阻塞一段时间,希望任务能够快速完成,然后备份到异步的方式。这可以使用get method taking a timeout作为参数来完成。

+2

我认为这解决了我的问题:目前我所有的方法都使用'SwingWorker's - 这似乎是一个问题,因为我必须等待结果。我将从这些方法中删除'SwingWorker'并且只调用一次,但同步执行'SwingWorker'内的所有内容。 – riwi

4

您可以使用异步范例。查看Observer/Observable并使用该作业将结果传回到当前正在进行轮询的对象。

+0

我想避免它,因为它会使我的代码非常复杂。我有几个短文件菜单操作(文件 - >打开,新建,关闭,保存,另存为,退出),依靠对方(即当试图退出,退出调用关闭,关闭可能会调用保存,保存可能会调用保存如)。 – riwi

+1

够公平的,它确实增加了复杂性,如果你打算连锁这样的运作,它可能不是理想的。 – mcfinnigan

4

使用worker.get()直接是行不通的,因为它会阻止EDT,等待完成的任务 - 这意味着即使我从SwingWorker中打开对话框不会得到画。

它们也不与当前代码一起使用。您忙于等待阻止EDT与调用worker.get()一样多 - 只有一个事件分派线程,并且SwingWorker中的对话框与该线程在循环中旋转或等待锁定一样被阻止。这里的问题是,如果一个方法运行在EDT上,它就不能从一个异步操作中返回一个值(不会占用EDT)给它的调用者。

对完成的异步处理作出反应的正确方法是覆盖SwingWorker中的done()方法。

也可以查看http://java.sun.com/products/jfc/tsc/articles/threads/threads2.html了解更多信息。

4

上面几位人员提到的一种方法是重写SwingWorker完成的方法。但是,如果由于某种原因,您希望将SwingWorker代码发布到SwingWorker外部和调用代码之外,则可以利用SwingWorker的属性更改支持。只需将一个PropertyChangeListener添加到SwingWorker中,并监听属性名称为“state”的state属性。然后可以使用getState()方法提取SwingWorker的状态。完成后,它将返回SwingWorker.StateValue枚举的DONE值。例如(从答案我在another thread给这里SO):

if (turn == white) { 
    try { 
     final SwingWorker<Move, Void> mySwingWorker = new SwingWorker<Move, Void>() { 
      @Override 
      protected Move doInBackground() throws Exception { 
       Engine e = new Engine(); // Engine is implemented by runnable 
       e.start(); 
       Move m = e.getBestMove(board);     
       return m; 
      } 
     }; 

     mySwingWorker.addPropertyChangeListener(new PropertyChangeListener() { 
      public void propertyChange(PropertyChangeEvent evt) { 
       if (StateValue.DONE == mySwingWorker.getState()) { 
       try { 
        Move m = mySwingWorker.get(); 

        // TODO: insert code to run on the EDT after move determined 

       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } catch (ExecutionException e) { 
        e.printStackTrace(); 
       } 
       } 
      } 
     }); 
     mySwingWorker.execute(); 

    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
    } 
0

我遇到了类似的问题,当我想要一个函数返回,将在挥杆工人来计算的值。我不想简单地通过这个线程来阻止EDT。我也不希望它阻止。所以我用这样的信号:

public boolean executeOperation() { 
    final Semaphore semaphore = new Semaphore(1); 
    semaphore.acquire(1); // surround by try catch... 
    final SwingWorker<Boolean, Void> worker = new SwingWorker<Boolean, Void>() { 
     @Override 
     protected Boolean doInBackground() throws Exception { 
      // .. 

      if (aborted) { 
       semaphore.release(); 
       return false; 
      } 

      // .. 
      semaphore.release(); 
      return true; 
     } 
    }; 

    worker.execute(); 



    try { 
     semaphore.tryAcquire(1, 600, TimeUnit.SECONDS); // awakes when released or when 10 minutes are up. 
     return worker.get().booleanValue(); // blocks here if the task doesn't finish in 10 minutes. 
    } catch (Exception e) { 
     // handle exceptions .. 
     return false; 
    } 
} 

我想这不是所有情况下的理想选择。但我认为这是一种替代方法,对我来说非常有用。