Планирование потоков Swingworker - PullRequest
2 голосов
/ 27 мая 2009

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

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

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

Ответы [ 4 ]

1 голос
/ 27 мая 2009

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

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

1 голос
/ 27 мая 2009

Как-то так, я думаю?

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 голосов
/ 12 апреля 2010

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

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

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

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

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

0 голосов
/ 27 мая 2009

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

fillList();
doStuffToList();

Или, может быть, что-то вроде:

doStuffToList(fillList());

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

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

...