Модераторы: LSD, AntonSaburov
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Обновление JTable внешним потоком. Проблемы синхронизации. 
:(
    Опции темы
COVD
Дата 19.12.2007, 16:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1655
Регистрация: 26.7.2005

Репутация: 4
Всего: 43



Такая проблема:

Внешний поток (команда с сервера) обновляет данные в таблице. Для примера, удаляет все строки. Выглядит примерно так:

Код

model.clear();//удаляем все из модели

// здесь модель уже пустая, а таблица еще не перерисована.

model.fireTableDataChanged();//ставим в очередь событие на перерисовку 


т.е. есть момент, когда визуальное представление не соответствует модели. Если в этот момент пользователь кликнет строчку (а ее уже нет в модели), то получим исключение (ArrayOutOfBounds). Самое простое решение, наверное, поймать это исключение и игнорировать его. Немного хуже, если удаляются не все строчки, а только некоторые. Тогда есть вероятность, что пользователь кликнет на строке, а в модели ей будет соответствовать уже другая, потому что строки в модели сдвинулись. В этом случае и исключения не будет, просто будет выбрана неверная строка. Ощущение, что JTable не "заточен" на обновления "снаружи". Или я ошибаюсь, "сам дурак" и т.д.?  
PM MAIL   Вверх
AlexeyVorotnikov
Дата 19.12.2007, 17:25 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 658
Регистрация: 18.6.2007
Где: Москва

Репутация: 3
Всего: 18



Все Swing компоненты не являются thread-safe.
Почитайте вот этот тьюториал: Concurrency in Swing


--------------------
RTFM!
Три источника и три составные части Java: The Java Language Specification, Java Platform API Specification, The Java Virtual Machine Specification
PM MAIL   Вверх
carper
Дата 20.12.2007, 09:34 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 227
Регистрация: 2.3.2005

Репутация: 4
Всего: 8



COVD

1. Думаю, что внешний поток не должен сам ничего делать, он должен отдавать команды модели таблицы (фокус в том, что надо иметь именно свою модель, которая знает, как надо правильно реагировать на clear), а уж она отлично знает, что дальше делать, например, синхронизировать на объекте всякие там getRow.
Т.е. мне кажется, что проблема несколько надумана.

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

Никакого отношения к JAVA это не имеет, я бы думал в плане, а почему это у меня строки удаляются так, что пользователь этого не видит или же успевает кликнуть не по той строке?
Скорее всего здесь грубая ошибка логики программы.

Как ни крутите, если у вас строки мутируют на глазах, то надо или смириться с этой фичей программы (например, на момент обновления взводить флаг, запрещающий/не реагирующий на щелчки по строкам), или что-то менять в интерфейсе.
PM MAIL   Вверх
COVD
Дата 20.12.2007, 17:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1655
Регистрация: 26.7.2005

Репутация: 4
Всего: 43



AlexeyVorotnikov 

Спасибо за ссылку на тюториал. Обратил внимание на SwingWorkers, которые пока никак не использовал.

carper 

Спасибо! Полностью с вами согласен. Пришел к аналогичным выводам. 
PM MAIL   Вверх
Dims
Дата 22.12.2007, 02:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1016
Регистрация: 21.11.2006

Репутация: 1
Всего: 11



В общем, насколько я понял, существует один поток, который называется EventDispatchThread, в котором выполняются все события, перерисовки и т.д. и т.п., то есть, всё графическое. Поскольку этот поток один, то заботиться о синхронизации не надо. Все методы Свинга небезопасны для многопоточности.

Если мы пишем поток, который должен посылать какие-то сообщения Свингу, то есть специальная статическая функция

Код

SwingUtilities.invokeLater(new Runnable() {
   public void run() {
    ...
   }
});


эта функция в текущем потоке выполняет только одно дейтсвие -- кладёт объект Runnable в очередь на исполнение в потоке EventDispatchThread. Текущий поток сразу же продолжает работу, а поток EventDispatchThread, когда дойдёт до события, выполнит его в себе, то есть, синхронно с остальным Свингом.

Недостаток этого метода в том, что если рабочий поток будет слишком быстро что-то делать, то он будет забивать очередь своими сообщениями и на нормальные сообщения Свинга будет оставаться меньше места.

Чтобы обойти эту проблему, можно использовать либо метод speep, чтобы поток спал после помещения события, либо аналогичную функцию invokeAndWait которая задерживает вызвавший поток до окончания исполнения события в потоке EventDispatchThread.

Добавлено через 1 минуту и 18 секунд
Здесь использован "встрочный анонимный" класс. То есть, наследник от Runnable создался прямо в тексте вызова функции.

Добавлено через 3 минуты и 2 секунды
Цитата(COVD @  20.12.2007,  17:19 Найти цитируемый пост)
Обратил внимание на SwingWorkers

По моему, он только в 6-й джаве. То есть, обратной совместимости может не получиться.
PM MAIL   Вверх
COVD
Дата 23.12.2007, 00:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1655
Регистрация: 26.7.2005

Репутация: 4
Всего: 43



Dims, если я правильно понял, вы полагаете, что если все делать через EventDispatchThread, то никаких проблем, кроме торможения GUI, не будет? Я думаю, даже это не поможет. Поможет только предложенное carper ("на момент обновления взводить флаг, запрещающий/не реагирующий на щелчки по строкам"), т.е. блокирование действий пользователя на время модификации модели таблицы и ее перерисовывания.

Например, в таблице три строки. 

Исполняется команда удалить вторую строку (пусть даже исполняется в EventDispatchThread ). Начинается все с удаления строки из модели. Начиная с этого момента пользователю должно быть запрещено "кликать" по строкам. Далее "зажигается" событие на перерисовку. Пока это событие не отработает ( пересчет индексов строк во внутреннем массиве таблицы  и перерисовка  таблицы - а это возможно еще одно событие в очередь) , пользователю не разрешено кликать, так как нарисованные строки уже не соответствуют модели. 

Если же ему разрешить и он кликнет на третью строку, то в очередь  встанет событие, указывающее на третью строку. А она переместилась на место второй в модели. Результат - ArrayOutOfBounds exception при обращении к модели при обработке события.

Как метко подметил carper, Java здесь ни при чем.



Это сообщение отредактировал(а) COVD - 23.12.2007, 00:42
PM MAIL   Вверх
Dims
Дата 23.12.2007, 20:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1016
Регистрация: 21.11.2006

Репутация: 1
Всего: 11



Цитата(COVD @  23.12.2007,  00:30 Найти цитируемый пост)
Исполняется команда удалить вторую строку (пусть даже исполняется в EventDispatchThread ). Начинается все с удаления строки из модели. Начиная с этого момента пользователю должно быть запрещено "кликать" по строкам.

А какой в этом смысл? Щелчки по строкам -- это события в очереди EventDispatchThread. Пока EventDispatchThread занят удалением строки, щелчок по строке никак не может быть обработан, поскольку он ещё не смотрит, что у него там дальше в очереди.

Цитата(COVD @  23.12.2007,  00:30 Найти цитируемый пост)
Если же ему разрешить и он кликнет на третью строку, то в очередь  встанет событие, указывающее на третью строку.

Разве? Мне кажется, не так. Пользователь кликнет в районе третьей строки, в очередь встанет событие мыши, в котором будут указаны лишь двухмерные координаты точки щелчка. Лишь потом, когда это событий дойдёт до какого-то элемента, оно будет конвертировано в событие тыкания в строку в EventDispatchThread. Но это произойдёт только после того, как EventDispatchThread уже удалит строку из модели. Поэтому, в момент конвертации третьей строки уже не будет и произойдёт тоже самое, что произойдёт, если пользователь ткнёт ниже последней строки.

PM MAIL   Вверх
COVD
Дата 26.12.2007, 04:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1655
Регистрация: 26.7.2005

Репутация: 4
Всего: 43



Цитата

Пользователь кликнет в районе третьей строки, в очередь встанет событие мыши, в котором будут указаны лишь двухмерные координаты точки щелчка. Лишь потом, когда это событий дойдёт до какого-то элемента, оно будет конвертировано в событие тыкания в строку в EventDispatchThread. Но это произойдёт только после того, как EventDispatchThread уже удалит строку из модели...
Поэтому, в момент конвертации третьей строки уже не будет и произойдёт тоже самое, что произойдёт, если пользователь ткнёт ниже последней строки.


Наверное, тут вы правы. Если событие клика встало в очередь после событий удаления, то, действительно, это похоже на клик мимо таблицы. Но ведь редактирование, если реализуется в EventDispatchThread, состоит из двух последовательных событий - сначала редактирование модели, потом оно зажигает второе событие (fireTableChange...) . Так события от мыши могут пролезть между ними в очередь. Соответственно, эти мышиные события будут иметь координаты момента времени когда модель уже изменена, а таблица еще не перерисована, т.е. M и V не соответствуют друг другу.

Надо поподробнее разобраться с EventDispatchThread. Спасибо.

Это сообщение отредактировал(а) COVD - 26.12.2007, 14:37
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   jk1
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, jk1.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java: GUI и Java FX приложения | Следующая тема »


 




[ Время генерации скрипта: 0.0546 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.