Ошибка пользовательского интерфейса при использовании ThreadPoolExecutor - PullRequest
0 голосов
/ 09 ноября 2011

Я использую ThreadPoolExecutor для реализации многопоточности.

Обычно каждому потоку назначается файл, который необходимо загрузить на сервер. После каждой успешной загрузки с сервера выдается уведомление.

Следующий код генерирует поток и присваивает ему файл.

Random random = new Random();
              ExecutorService executor = new ThreadPoolExecutor(5, 5, 50000L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(400));

        int waitTime = 100;
        while (it.hasNext()) {

            int time = random.nextInt(1000);
            waitTime += time;
            newFile = new File((String) it.next());
            executor.execute(new Runnable() {

                @Override
                public void run() {

                    processFile(newFile);
                }
            });
            try {
                Thread.sleep(waitTime);
            } catch (Exception e) {
            }

        }

        try {
            Thread.sleep(waitTime);
            executor.shutdown();
            executor.awaitTermination(waitTime, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
        }

Я создал Java-апплет для рендеринга пользовательского интерфейса. После каждого уведомления я обновляю состояние файла в окне Java-апплета, где updateUI () вызывается из processFile ().

Перед использованием ExecutorService (рекомендуется для обработки многопоточности на Java v5.0 и выше) я использовал класс Thread для создания потоков и ожидания-уведомления для функции загрузки файлов. Пользовательский интерфейс, отображающий каждое состояние обновления файла, корректно отображается при использовании класса Thread, но при использовании ExecutorService все файлы загружаются (функциональность работает), но пользовательский интерфейс зависает.

После успешной загрузки каждого файла необходимо обновить состояние загрузки файла для каждого из файлов.

Любые предложения / советы приветствуются.

1 Ответ

0 голосов
/ 09 ноября 2011

для обновления пользовательского интерфейса из потока, не являющегося EDT (потока событий, который вызывает обработчики событий и т. Д.), Вам необходимо использовать SwingUtilities.invokeLater(Runnable)

и вы НИКОГДА не должны спать на EDT или блокировать его, так как именно он гарантирует, что все реагирует

однако было бы лучше использовать SwingWorker , поскольку это реализует несколько вещей, специфичных для использования фоновых потоков, которые должны обновлять графический интерфейс

с SwingWorker ваш код будет

while (it.hasNext()) {

    final File newFile = new File((String) it.next());
    SwingWorker<Void,Void> work = new SwingWorker<Void,Void>(){

        @Override
        public Void doInBackground() {

            processFile(newFile);//do **not** call updateUI() in here
            return null;
        }

        @Override
        protected void done(){//this gets called after processFile is done on the EDT
            updateUI();
        }
    }).execute();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...