2012-03-28 90 views
6

考虑下面的代码:在SwingWorker内部运行ExecutorService是一种很好的做法吗?

 SwingWorker<Void, Void> sworker = new SwingWorker<Void, Void>() { 

     @Override 
     protected Void doInBackground() throws Exception { 
      ExecutorService executor = Executors.newFixedThreadPool(5); 
      try { 
       for (int j = 0; j < 5; j++) { 
        Callable<Object> worker = new MyCallableImpl(); 
        Future<Object> future = executor.submit(worker); 
        array[j] = future.get(); 
       } 
      } catch (InterruptedException e) { 
       // some code here 
      } catch (ExecutionException e) { 
       // some code here 
      } 
       // some code here 
      executor.shutdown(); 
      return null; 
     } 

    }; 
    sworker.execute(); 

正如我在标题中说:这是调用内部doInBackground SwingWorker类的()方法的ExecutorService一个好的做法呢?这对我的作品(JDK1.7),GUI不会被阻止,并从执行人池多个线程在后台运行的,但我仍然有一些疑惑...

回答

2

上面的代码并没有多大意义了我。

如果这里的目标是确保在执行长时间运行的任务时GUI保持响应,那么因为SwingWorker已经提供了该机制,所以不需要使用ExecutorService

+0

是的,我知道,但我想在SwingWorker中运行多个线程(Callables)。我该如何做到这一点,而不必在SwingWorker中包装Executor? – DoktorNo 2012-03-28 14:55:53

+0

我只是摆脱'SwingWorker'然后。如果任何的这些任务修改摇摆成分(S),使用'SwingUtilities.invokeLater' – mre 2012-03-28 14:58:13

+0

是的,他们正在修改Swing组件包裹该呼叫(未示出代码,以避免混淆)。我会在此期间尝试您的解决方案。 – DoktorNo 2012-03-28 15:00:31

2

为了进一步MRE的响应。它没有意义,因为你的执行实际上是单线程的。 doInBackground将提交给执行者并等待完成该单个任务,然后再提交另一个任务。

您应该以同样的方式提交,但将返回的Future存储在某种列表中,然后在提交所有任务后获取其中的每一个。

我不一样多介意doInBackground为MRE做异步提交这些作业。如果您正在尝试提交多项任务,并且在任何给定时间只提交了N个,那么您绝对不应该通过SwingWorker.doInBackground来完成此操作。使用​​我认为是更好的方法。

只是为了澄清任何混淆,invokeLater应该只在这里使用时,在ExecutorService中的任务是完整的,它所需要做的就是更新UI组件。

编辑:示例解决您的评论

protected Void doInBackground() throws Exception { 
    ExecutorService executor = Executors.newFixedThreadPool(5); 
    List<Future> futures = ...; 
    try { 
     for (int j = 0; j < 5; j++) { 
      Callable<Object> worker = new MyCallableImpl(); 
      futures.add(executor.submit(new Callable<Object>(){ 
       public Object call(){ 
        //expensive time consuming operation 
        final String result = ...;//result from consuming operation 
        SwingUtilities.invokeLater(new Runnable(){ 
         public void run(){ 
          jLabel.setText(result); 
         } 
        }); 
        return new Object(); 
       } 
      )); 
     } 
     for(Future<Object> f :futures)f.get(); 
     executor.shutdown(); 
    return null; 
} 

注意如何invokeLater做是为了做一个简单的更新?这不应该导致你的EDT冻结。

+0

我会试试这个。顺便说一句,SwingUtilities.invokeLater()和EventQueue.invokeLater()有什么区别? – DoktorNo 2012-03-28 15:27:47

+0

在标准的Java发行版中,什么也没有。 'SwingUtilities.invokeLater'只是委托给'EventQueue.invokeLater'。只需将所有必要的功能连接到SwingUtilities。 – 2012-03-28 15:30:10

+0

我在invokeLater中封装了所有更改GUI的调用,它们在anonymour Runnable中,并且GUI仍处于锁定状态。我做错了什么?顺便说一句:整个代码从我的代码片段运行在事件监听器调用的方法中(按下按钮之后)。 – DoktorNo 2012-03-28 15:49:46

2
  • 可以从执行器执行SwingWorkers例如

  • 不得不接受这样执行人不关心SwingWorkers生命周期,反之亦然

  • 必须实现的PropertyChangeListener的SwingWorker的

  • exmple here

相关问题