Использование нескольких потоков в программе Java и необходимость создания объектов Swing в EDT

Re: Требование создать объект Swing в потоке отправки событий.

Я работаю над приложением, целью которого является мониторинг и отображение состояния различных удаленных встроенных серверов. Я довольно новичок в Java, и мое понимание требований в отношении объектов Swing и EDT является неполным.

Основной графический интерфейс запускается в EDT обычным образом следующим образом:

    javax.swing.SwingUtilities.invokeLater(new Runnable() {

        public void run() {
            createAndShowGUI();
        }
    });

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

                new Thread(new VoterStatus(itemNumber)).start();

который вызывает метод «запуска» класса VoterStatus, который, в свою очередь, создает новое окно с JFrame. Новый поток, экземпляр класса VoterStatus, затем опрашивает (TCP и т. д.) конкретный указанный удаленный объект (itemNumber), собирая различные биты информации и отображая их в JFrame.

Может быть любое количество таких потоков, соответствующих экземпляру VoterStatus, каждый из которых обновляет свои собственные окна. Нет обмена данными между этими различными окнами/JFrame/задачами.

Кажется, это работает нормально, но безопасно ли?

Нарушил ли я правило создания компонентов Swing в EDT?

Будет ли полезно использование класса SwingWorker?

Я был бы признателен за любые комментарии от программистов Java, более опытных в таких вопросах.

Спасибо, Стив.


person Steve    schedule 01.02.2011    source источник
comment
Вы используете EDT только для запуска основного графического интерфейса? Если да, то все в порядке. Но если последующие окна также создаются в EDT, и их создание достаточно долгое (например, > 200 мс), ваш графический интерфейс зависнет на время создания нового окна.   -  person Rogach    schedule 01.02.2011
comment
Привет, Рогач. Эти комментарии немного расходятся с парой других ответов, хотя я бы предпочел, чтобы это было так. Я создаю основной графический интерфейс в EDT, но другие окна запускаются в потоках, запущенных в EDT. Есть еще мысли. Спасибо, Стив.   -  person Steve    schedule 02.02.2011


Ответы (4)


Из раздела руководства Swing под названием Поток отправки событий.

Некоторые методы компонентов Swing помечены как "потокобезопасные" в спецификации API; их можно безопасно вызывать из любого потока. Все остальные методы компонентов Swing должны вызываться из потока диспетчеризации событий. Программы, игнорирующие это правило, в большинстве случаев могут работать корректно, но подвержены непредсказуемым ошибкам, которые трудно воспроизвести.

Я всегда вызываю свои методы в EDT, чтобы не тратить время на погоню за гремлинами.

Редактировать:

Я только что прочитал другую публикацию, в которой говорится, что комментарий «потокобезопасный» был удален из многих методов в API JDK7. http://forums.oracle.com/forums/thread.jspa?threadID=2167051 . Это выглядит как еще одна причина убедиться, что все методы, влияющие на графический интерфейс, выполняются в EDT.

person camickr    schedule 01.02.2011
comment
+1 Как и орбитальная бомбардировка, это единственный способ убедиться. :-) - person trashgod; 01.02.2011
comment
repaint() — хороший пример метода, который всегда безопасно запускать вне EDT. - person Erick Robertson; 01.02.2011

@camickr имеет на это право. Неправильно синхронизированные программы могут казаться работающими большую часть времени, но результат ненадежен. Несколько связанных подходов обсуждаются здесь. SwingWorker — особенно удобная реализация < интерфейс href="http://download.oracle.com/javase/6/docs/api/java/util/concurrent/Future.html" rel="nofollow">Future, так как process() работает на поток отправки событий.

person trashgod    schedule 01.02.2011

Вы можете быть в безопасности, но вы можете быть уверены, создав другие компоненты пользовательского интерфейса в EDT, как вы это сделали для основного приложения.

Однако я бы предложил другой подход. Вместо запуска нового Thread, который создает окна и прочее для каждого нового VoterStatus, создайте компоненты пользовательского интерфейса в EDT в ответ на ActionEvents из меню или чего-то еще, и выполняйте обработку сетевого материала только в другом потоке. Затем получите результаты и используйте EDT для их отображения. Как вы сказали, SwingWorker идеально подходит для этого - именно для этого он и был разработан. Для меня это представляет собой более четкое разделение, максимально отделяющее пользовательский интерфейс от сетевого.

person Stewart Murrie    schedule 01.02.2011

На самом деле я не отвечаю на свой вопрос, но я хочу поблагодарить тех, кто ответил, и задать один или два дополнительных вопроса.

Рогаш прокомментировал, что если бы я создавал только графический интерфейс на EDT, все было бы в порядке, но это не совсем соответствует строгому толкованию правила?

Дополнительные потоки создаются в EDT, но они по-прежнему являются отдельными потоками.

Хотя может быть желательным немного лучшее разделение графического интерфейса и связи, я ожидаю, что это значительно усложнит основной код графического интерфейса, поскольку ему придется определять, какое окно вызвало различные события, а затем обновлять правильное окно, не говоря уже о связи между различные потоки и основной поток GUI. Возможно, я преувеличиваю эту сложность (я еще не разработал и не думал о том, как ее закодировать), но это может показаться более сложным. Каждый из потоков/JFrame уже имеет пару массивов JToggleButton (30 элементов), вызывающих потенциальные события, и около 10 массивов JTextField с таким же количеством элементов, требующих обновления.

Конечно, если мой метод небезопасен, мне придется его изменить, и все!

На самом деле, мне интересно, может быть, мне лучше оставить все как есть и использовать мьютекс или семафор, чтобы убедиться, что только один поток обращается к методам Swing в каждый момент времени. На самом деле нет длительных действий пользователя или любой другой активности, занимающей много времени, просто принимается множество пакетов TCP или UDP, которые требуют обновления экрана.

Еще раз спасибо Стив

PS Пробовал зарегистрироваться на этом форуме, но думаю это обсуждение останется под моей незарегистрированной персоной.

person Steve    schedule 02.02.2011