Обязательно ли использовать Runnable.run при вызове метода done из SwingWorker - PullRequest
1 голос
/ 26 февраля 2020

В рамках изучения SwingWorker я изучал исходный код, в котором обнаружил приведенный ниже код. У меня есть вопрос по этому поводу.

private void doneEDT() {
        Runnable doDone =
            new Runnable() {
                public void run() {
                    done();
                }
            };
        if (SwingUtilities.isEventDispatchThread()) {
            doDone.run();
        } else {
            doSubmit.add(doDone);
        }
    }

Вышеупомянутый doneEDT вызывается из конструктора SwingWorker, как показано ниже:

public SwingWorker() {
        Callable<T> callable =
                new Callable<T>() {
                    public T call() throws Exception {
                        setState(StateValue.STARTED);
                        return doInBackground();
                    }
                };

        future = new FutureTask<T>(callable) {
                       @Override
                       protected void done() {
                           doneEDT();
                           setState(StateValue.DONE);
                       }
                   };

       state = StateValue.PENDING;
       propertyChangeSupport = new SwingWorkerPropertyChangeSupport(this);
       doProcess = null;
       doNotifyProgressChange = null;
    }

Вопрос

Почему метод done() обернутый внутри Runnable в методе doneEDT ?. Метод done() можно вызывать напрямую, не заключая его в Runnable верно? Так что я подумал, какое преимущество заключает его в Runnable?

Итак, этот вопрос возник у меня в голове.

1 Ответ

0 голосов
/ 09 апреля 2020

Вы объединяете два разных done() метода. Один из SwingWorker, который вы собираетесь переопределить. Ничего особенного с Runnable не должно произойти в вашей реализации done(), только ваш собственный код. (Надежная реализация done() проверит на isCancelled, возможно, вызовет get(), если вы не вызываете его в другом месте, и обработает все исключения, которые могли быть выданы работником, и т. Д. c. Но вы не Чтобы сделать что-нибудь из этого, нужно обернуть Runnable.)

Другой метод - FutureTask. Это сбивает с толку, потому что SwingWorker сам использует FutureTask для выполнения «реальной» работы по параллелизму. FutureTask#done() - это , также , предназначенный для переопределения клиентами, но в этом случае клиентом является SwingWorker, а не вы.

Когда вы вызываете execute (), SwingWorker's future ( частная переменная экземпляра FutureTask) запускается, и вот что происходит:

  • future.run() выполняется в рабочем потоке.

  • future.run() вызывает Callable, переданный, как вы цитировали выше, изменяя состояние на STARTED (которое отправляет событие свойства) и вызывая doInBackground. Ваш собственный рабочий код запускается и возвращает результат.

  • future.run() вызывает собственный метод 'set' для сохранения результата и пометки вычисления как завершенного. Он также вызывает закрытый метод finishCompletion.

  • future.finishCompletion(), который пробуждает любые другие потоки, которые вызвали SwingWorker's get() (и поэтому были заблокированы все это время). Эти вызовы get() могут возвращать результат вычисления своим абонентам одновременно с остальной частью этого списка.

  • future.finishCompletion() вызывает свой собственный done(). Обычно это пустой метод, но, как вы цитировали выше, SwingWorker сделал переопределение. Так что этот конкретный FutureTask done() делает еще две вещи: во-первых, он вызывает SwingWorker#doneEDT(), который просто вызывает SwingWorker#done() в потоке диспетчеризации событий. Это версия done(), которую вы переопределяете в своем подклассе SwingWorker. А во-вторых, он изменяет состояние на DONE, которое отправляет другое событие изменения свойства.

  • future s finishCompletion() возвращается к своему методу set, который возвращает к run() , который занимается уборкой и возвращается. В этот момент рабочий поток освобождается для других целей (новые рабочие места, сон, хобби и т. Д.).

Ваше участие будет только в SwingWorker's done(), если вы хотел подкласс это. Благодаря манипулированию SwingWorker, ваше собственное переопределение done() гарантированно будет выполнено в потоке диспетчеризации событий, так что вы можете безопасно работать с визуальными компонентами Swing. Имейте в виду, что done() также вызывается в случае отмены SwingWorker, даже если cancel() был вызван до execute() - фактически, done() вызывается до того, как cancel() возвращается - так что проверьте соответствующий статус внутри вашего переопределить.

...