Вопрос

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

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

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

Это было полезно?

Решение

Я думаю, что-то вроде этого подойдет?

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
                }
            }
        }
    }
    ...
}

Другие советы

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

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

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

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

На мой взгляд, это довольно просто, потому что в нашем случае 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 в цепочке, становится довольно легко реализовать.

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

fillList();
doStuffToList();

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

doStuffToList(fillList());

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top