2009-05-27 4 views
2

У меня есть 2 процесса для выполнения в моем приложении swing, один для заполнения списка и один для выполнения операций над каждым элементом в списке. Я только что переместил 2 процесса в потоки Swingworker, чтобы остановить блокировку GUI во время выполнения задач, и потому что мне нужно будет сделать этот набор операций для нескольких списков, поэтому параллелизм не будет плохой идеей в первом место. Однако, когда я только что закончилПланирование потоков Swingworker

fillList.execute();
doStuffToList.execute();

поток doStuffToList для запуска в пустом списке (duh ...). Как сказать второму процессу ждать, пока первый не будет выполнен? Полагаю, я мог бы просто вложить второй процесс в конце первого, но я не знаю, это похоже на плохую практику.

+1

Похоже, что BlockingQueue может быть полезным (http://java.sun.com/javase/6/docs/api/java/util/concurrent/BlockingQueue.html). –

ответ

1

Что-то вроде этого сделало бы это, я думаю?

boolean listIsFull=false; 
class FillListWorker extends SwingWorker<Foo,Bar> 
{ 
    ... 
    protected void done() 
    { 
     synchronized (listYouveBeenFilling) 
     { 
      listIsFull=true; 
      listYouveBeenFilling.notifyAll(); 
     } 
    } 
    ... 
} 

class DoStuffToListListWorker extends SwingWorker<Foo,Bar> 
{ 
    ... 
    protected Foo doInBackground() 
    { 
     synchronized (listYouveBeenFilling) 
     { 
      while (!listIsFull) 
      { 
       try 
       { 
        listYouveBeenFilling.wait(); 
       } 
       catch (InterruptedException ie) 
       { 
        // Don't worry, we'll just wait again 
       } 
      } 
     } 
    } 
    ... 
} 
+0

Мне нравится это решение для большинства из опубликованных, но это не сработает для меня, потому что 'listIsFull' должен быть окончательным, поскольку он доступен из внутреннего класса ..., что делает невозможным изменение значения позже, как вы пытаетесь сделать. – The111

+0

Это нужно только «final», если вы определяете его в рамках метода. Если вы определяете его как поле члена внешнего класса, все будет хорошо. –

-1

Чтобы выполнить два процесса последовательно, традиционно вы просто вызываете один метод за другим (!).

fillList(); 
doStuffToList(); 

Или, возможно, что-то вроде:

doStuffToList(fillList()); 

Если вы обрабатываете один за один раз, вы можете два потока с BlockingQueue между ними. Вы можете пойти дальше, имея несколько потоков do-stuff.

Что касается сообщения об отключении события AWT (EDT), то он просто отключен от действия без блокировки и будет уведомлен позже.

+0

Это не соответствует тому, что SwingWorker # execute возвращается немедленно. ОП четко знает, как вызвать одну функцию за другой в целом. –

1

Как сообщить второму процессу ждать, пока первый не будет выполнен? Полагаю, я мог бы просто вложить второй процесс в конце первого, но я не знаю, это похоже на плохую практику.

Вы изучали использование флагов вместо звонков &? Они кажутся хорошим совпадением для такого рода вещей (позволяя doStuffToList работать с Future.get() вместо фактического списка, поэтому он будет готов, когда будет вызван get), кроме всего бизнеса swingworker .. (Рассмотрим это предложение, а не ответ)

+0

Это может быть именно то, что я хочу, я сейчас изучаю его, спасибо – Simonw

0

у нас есть что-то вроде этого:

private SwingWorkerExecutor swingWorkerExecutor; 

//... 

protected void runChain(List<SwingWorker<Void>> chainWorkers, 
         final SwingWorkerExecutor.RunAfter<Void> runAfter, 
         final SwingWorkerExecutor.RunOnError runOnError) 
{ 
    final List<SwingWorker<Void>> remainingWorkers = 
     chainWorkers.subList(1, chainWorkers.size()); 
    SwingWorkerExecutor.RunAfter<Void> chainRunAfter; 
    if (chainWorkers.size() > 1) 
    { 
     chainRunAfter = new SwingWorkerExecutor.RunAfter<Void>() 
     { 
      @Override 
      public void run(Void value) 
      { 
       runChain(remainingWorkers, runAfter, runOnError); 
      } 
     }; 
    } 
    else 
    { 
     chainRunAfter = runAfter; 
    } 

    currentWorker = chainWorkers.get(0); 

    swingWorkerExecutor.execute(currentWorker, chainRunAfter, runOnError); 
} 

Это довольно просто, IMO, потому что в нашем случае SwingWorkerExecutor фактически содержит все трудно понять, есть:

public class DefaultSwingWorkerExecutor implements SwingWorkerExecutor 
{ 
    @Override 
    public <T> void execute(SwingWorker<T, ?> worker, RunAfter<T> after, 
          RunOnError onError) 
    { 
     worker.addPropertyChangeListener(
      new RunAfterHandler<T>(worker, after, onError)); 
     worker.execute(); 
    } 

    private static class RunAfterHandler<T> implements PropertyChangeListener 
    { 
     private final SwingWorker<T, ?> worker; 
     private final RunAfter<T> after; 
     private final RunAfter<Throwable> onError; 

     protected RunAfterHandler(SwingWorker<T, ?> worker, RunAfter<T> after, 
            RunOnError onError) 
     { 
      this.worker = worker; 
      this.after = after; 
      this.onError = onError; 
     } 

     @Override 
     public void propertyChange(PropertyChangeEvent evt) 
     { 
      if ("state".equals(evt.getPropertyName()) && 
       evt.getNewValue() == SwingWorker.StateValue.DONE) 
      { 
       if (worker.isCancelled()) 
       { 
        return; 
       } 

       try 
       { 
        after.run(worker.get()); 
       } 
       catch (InterruptedException e) 
       { 
        Thread.currentThread().interrupt(); 
       } 
       catch (ExecutionException e) 
       { 
        onError.run(e); 
       } 
      } 
     } 
    } 
} 

Есть некоторые недостающие интерфейсы, которые h должен быть довольно прямолинейным, чтобы писать, не видя их здесь.

Наше настоящее развертывание SwingWorkerExecutor выполняется с использованием внедренного ExecutorService вместо стандартного (это уменьшает количество пулов потоков, которые необходимы для одного приложения). Но настоящая причина, по которой мы ввели SwingWorkerExecutor, заключалась в том, что она упрощает и стандартизирует обработку SwingWorker и условия ошибки, а также позволяет заменить логику модульных тестов (которые, как я уверен, вы знаете, намного проще, если они однопоточные.) Как вы можете видеть, есть куча шаблонов, которые вам обычно нужны для каждого SwingWorker внутри done(), поэтому вместо этого мы перемещаем работу done() в обратный вызов.

Боковое преимущество заключается в том, что такие вещи, как запуск нескольких рабочих Swing в цепочке, становятся довольно простыми в реализации.

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