Графический интерфейс не работает при запуске синхронизированного метода

У меня есть приложение с основным объектом (содержащим графический интерфейс Swing) и вспомогательный поток, который вызывает метод handle() объекта.

Я заметил, что когда метод handle() синхронизирован, а поток использует метод handle(), графический интерфейс основного объекта не отвечает. Код:

public synchronized void handle()){
//method code
}

я удаляю синхронизированное ключевое слово из handle(), графический интерфейс реагирует, даже когда поток использует метод handle().

Интересно отметить, что когда я использовал другой объект в качестве блокировки, графический интерфейс снова становится отзывчивым, когда поток использует метод handle(). Код:

public void handle(){
    synchronized(anotherObj){
    //method code
    }
}

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

Спасибо.


person Wor White    schedule 31.07.2011    source источник


Ответы (1)


Каков ваш метод «ручки» и что он делает? Я полагаю, что Swing по большей части не использует синхронизацию, и его документация фактически указывает в его API, что он не является потокобезопасным (например, посмотрите здесь). Вместо этого он использует один поток для взаимодействия с пользователем и отрисовки программы, EDT или Поток диспетчеризации событий, и все программы, взаимодействующие с Swing, должны соблюдать эту модель одного потока, вызывая большинство всех вызовов Swing в EDT. Я подозреваю, что именно в этом и заключается ваша проблема.

Дополнительные сведения о многопоточности Swing и использовании фоновых потоков см. здесь: Параллелизм в Swing

Редактировать 1
(из моего комментария) Я также должен спросить, почему этот метод синхронизирован? Поскольку мы ставим все вызовы Swing в очередь событий, в этом, вероятно, нет необходимости и, возможно, это вредно. Зависание программы Swing почти всегда происходит из-за проблемы параллелизма, поэтому это обсуждение актуально.

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

person Hovercraft Full Of Eels    schedule 31.07.2011
comment
@Амир: спасибо. Вы имеете в виду, что у вас осталось всего 7 голосов? - person Hovercraft Full Of Eels; 31.07.2011
comment
Ах, я уже рассмотрел EDT. Но, похоже, это не дает никакого представления о том, почему это так. Дескриптор в основном обрабатывает ввод и отправляет ответ сервера — он не имеет ничего общего с графическим интерфейсом. Но не должно иметь значения, что делает дескриптор - разница только в синхронизации. - person Wor White; 31.07.2011
comment
@worwhite: но это имеет значение. Выполняете ли вы вызовы Swing из метода handle (скорее всего, да) и убедитесь, что он вызывается в EDT? Кроме того, почему этот метод синхронизирован? Поскольку вы ставите все вызовы Swing в очередь событий, это, вероятно, не нужно и, возможно, вредно. Возможно, вы захотите сделать небольшую компилируемую программу, которая демонстрирует ваше замораживание, и опубликовать ее здесь, чтобы мы могли протестировать ее сами. - person Hovercraft Full Of Eels; 31.07.2011
comment
Хм, дескриптор иногда вызывает другой метод (не синхронизированный), который вызывает textArea.append() и textField.setText(). Но в этом случае использование другого объекта в качестве блокировки все равно должно вызывать зависание, верно? Метод синхронизирован, поскольку к нему обращаются другие потоки, что может привести к помехам. Это серверная часть клиент-серверной программы. Боюсь, это слишком сложно для публикации. - person Wor White; 31.07.2011
comment
Я не прошу вас выкладывать вашу программу, просто небольшую тестовую программу, которая демонстрирует проблему. Длительную задачу можно имитировать с помощью Thread.sleep(...). - person Hovercraft Full Of Eels; 31.07.2011
comment
Я знаю... преобразование его в небольшую программу тоже заняло бы слишком много времени. Что я могу сделать сейчас, так это удалить все свинг-вызовы, к которым косвенно обращаются с помощью handle(), и проверить это. - person Wor White; 31.07.2011
comment
@Wor, вам нужно сделать две вещи: во-первых, убедиться, что handle не вызывается обработчиком событий, то есть убедиться, что handle не работает в EDT. Во-вторых, поместите обновления пользовательского интерфейса в Runnable и вызовите их, используя SwingUtilities.invokeLater(). - person Paul; 31.07.2011
comment
Сделаю через пару часов и выложу результаты. Спасибо. - person Wor White; 31.07.2011
comment
@Hovercraft - мне нужно было столько букв, чтобы оставить комментарий. - person Amir Afghani; 31.07.2011
comment
Хорошо, я сделал несколько тестов. Это оскорбительная строка в handle(): textArea.setCaretPosition(length); где длина постоянно увеличивается. Если длина заменена константой (например, setCaretPosition(0)) или если вся эта строка удалена, зависание не происходит, даже если handle() синхронизируется. Удивительно, но эта строка не вызывает зависания, если handle() не синхронизирован или синхронизирован с другим объектом (objLock). - person Wor White; 01.08.2011