2012-03-28 5 views
6

Рассмотрим следующий код:Выполняет ли ExecutorService внутри SwingWorker хорошую практику?

 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(); 

Как я уже говорил в названии: это хорошая практика, чтобы вызвать ExecutorService внутри doInBackground метода() из SwingWorker? Это работает для меня (JDK1.7), GUI не заблокирован, и несколько потоков из пула Исполнителей работают в фоновом режиме, но все же у меня есть некоторые сомнения ...

ответ

2

Вышеприведенный код для меня не имеет смысла.

Если целью является обеспечение того, чтобы GUI оставался отзывчивым при выполнении долговременной задачи, тогда нет необходимости использовать ExecutorService, поскольку SwingWorker уже предоставляет этот механизм.

+0

Да, я знаю это, но я хочу запустить несколько потоков (Callables) внутри SwingWorker. Как я могу сделать это без ненужной упаковки Executor внутри SwingWorker? – DoktorNo

+0

Тогда я просто избавился бы от «SwingWorker». Если какая-либо из этих задач изменит компонент Swing, заверните вызов, используя 'SwingUtilities.invokeLater' – mre

+0

Да, они изменяют компоненты Swing (код не отображается, чтобы избежать путаницы). Я попробую ваше решение тем временем. – DoktorNo

2

Для дальнейшего ответа от mre. Это не имеет смысла, потому что ваше исполнение на самом деле однопоточное. doInBackground отправит исполнителю и дождитесь завершения этой отдельной задачи, а затем отправьте другое.

Вы должны отправить таким же образом, но сохраните возвращенный Future s в списке какого-либо рода, затем перейдите по каждому из них после отправки всех заданий.

Мне не так нравится doInBackground, чтобы отправить эти задания асинхронно, как это делает mre. Если вы пытаетесь отправить несколько заданий и только в течение определенного времени подали только N, вам определенно не следует делать это через SwingWorker.doInBackground. Использование ExectorService + SwingUtilities.invokeLater Я думаю, что это лучший способ.

И как раз для того, чтобы разъяснить любую путаницу, invokeLater следует использовать здесь только тогда, когда задача в ExecutorService завершена, и все, что нужно сделать, это обновить компонент пользовательского интерфейса.

Edit: Пример решения Ваш комментарий

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

+0

В стандартном дистрибутиве Java ничего. 'SwingUtilities.invokeLater' просто делегирует' EventQueue.invokeLater'. Просто объединяет все необходимые функции в SwingUtilities. –

+0

Я завернул все вызовы для изменения GUI в invokeLater, внутри анонимного Runnable и GUI все еще заблокирован. Что я сделал не так? BTW: весь код из моего фрагмента запускается в методе, вызванном прослушивателем событий (после нажатия кнопки). – DoktorNo

2
  • может SwingWorkers выполнение экземпляра из Исполнителю

  • должны принимать, что Исполнитель не заботится о SwingWorkers жизненного цикла, и наоборот

  • должны реализовать PropertyChangeListener для SwingWorker

  • exmple here

Смежные вопросы