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

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Синхронизация коллекция в Java 
V
    Опции темы
novichiok
Дата 16.10.2011, 14:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Здравствуйте,
Помогите пожалуйста, разобраться с синхронизацией коллекций в Java
Просьба: если захотите ответить, дочитайте, пожалуйста весь пост до конца, там изложены кое - какие мои соображения, и хотелось бы услышать 
ваше мнение по ним. Я постарался как можно четче изложить суть некоторых моих сомнений.
Спасибо.

Начну вопрос с моего понимания смысла существования необходимости синхронизации...
Для чего вообще предназначена синхронизация...
В моем понимании для 2 вещей - 1) сохранение целостности данных с точки зрения самой программы.(Я имею ввиду что если,с точки зрения программы, определенная 
группа операций должна выполняться как единая транзакция, то есть для программы быть *атомарной* то такую группу нужно синхронизировать)
2) сохранение целостности структур данных с точки зрения JVM(имею ввиду избежания всякого рода ConcurrentModificationException и тд)

Вот цитаты из javadoc для ArrayList и HashMap
ArrayList - 
If multiple threads access an ArrayList instance concurrently, and at least one of the threads modifies 
the list structurally, it must be synchronized externally. (A structural modification is any operation that 
adds or deletes one or more elements, or explicitly resizes the backing array; merely setting the value of an 
element is not a structural modification.)

то есть, как я понимаю, операцию set() синхронизировать не нужно? 

HashMap - 
If multiple threads access a hash map concurrently, and at least one of the threads modifies the map structurally, it must be synchronized externally. (A structural modification is any operation that adds or deletes one or more mappings; merely changing the value associated with a key that an instance already contains is not a structural modification.)

то есть, как я понимаю, я могу *потокобезопасно* читать с Мапа, и кроме того !!! *потокобезопасно* модифицировать value для этого метода, при этом ничего 
не синхронизировав ?

У меня по этому поводу возникло 2 вопроса и несколько выводов

Допустим у меня в программе невозможно отказаться от обычных структур данных(не использовать synchronized* структуры, ,блокирующие очереди ConcurrentAPI
и тд, НУ допустим так... ) 
1) множеством потоков я читаю из HashMap и одним-единственным модифицирую value для уже имеющегося ключа, то есть я не удаляю/добавляю мапинги, а просто 
привязываю к ключу новый value. В таком же случае,судя по javadoc, синхронизировать доступ к Мапу не нужно, так ведь? А что если я начну модифицировать values 
для мапа не 1 а несколькими потоками ? Опять таки,судя по javadoc, это не структурная операция => её синхронизировать не нужно, так ? Ну а вот ,вдруг,будет 
такая ситуация, что сразу 2 модифицирующих потока будут писать значения по одинаковому ключу, что тогда ? Я предполагаю, что с точки зрения сохранности *моих*
данных - будет плохо,но JVM считает что это уже *мои* проблемы, а с точки зрения JVM такое поведение допустимо и никаких Exceptions сгенерированно не будет. 
Я прав?
СМ: PS
2) такая же ситуация что и в предыдущем вопросе. На сей раз ArrayList. Судя по Javadoc я без проблем могу читать из него несколькими потоками, ничего не синхронизируя. Опять таки там пишется, что запись элемента под уже существующем индексом - не структурая операция. Следовательно с точки зрения
JVM set() тоже можно не синхронизировать.
Давайте посмотрим на код set() из ArrayList :
Код

public E set(int index, E element) {
    RangeCheck(index);

    E oldValue = (E) elementData[index];
    elementData[index] = element;
    return oldValue;
    }

Понятно, что с точки зрения *моих* данных, хранящихся в этом ArrayList асинхронный set() смерти подобен,в том случае если я полагаюсь на 
значение возвращаемое setом,ведь допустим ситуацию - 
поток1 заходит в set() выполняет строку4 и вытесняется, после чего поток2 проходит весь set() полностью,после чего раздупляется поток1 ставит свой element
и возвращает значение установленное не потоком2 а то которое он забрал до захода потока2 в set(). 
Объяснение такой трактовки в javadoc вижу такое же, как и описанно в вопросе выше (1) : с точки зрения JVM все корректно: мол - ну ставят несколько потоков 
разные значения , ну и что ?...
Посмотрите,пожалуйста, секцию PS где я пишу из-за чего,по моему  мнению, так происходит.

Мой вывод1 - для того чтоб не развалить сам *JVM* ConcurrentModificationExceptionоами и прочим, синхронизировать нужно *только* *структурные* операции
вывод2 - если ты просто читаешь с структуры - синхронизация не обязательна
           - если читаешь и пишешь(изменяешь структурно) обязательная синхронизация, чтоб не развалилась JVM и данные программы были в целостности
           - если пишешь(не структурно) *НО* с точки зрения программы данные могут быть поврежденны(то есть группа операций по модифицированию данных 
*обязательно* должна выполнятся атомарно) нужно синхронизириовать(локами, синхронайзом методов, синхронизированными блоками и тд)
           - если читаешь и пишешь(не важно структурно или нет) синхронизировать нужно readWriteLock'ом
 
PS: может, такие строки(СМ пункты javadoc выше) есть в javadoc из-за того что с точки зрения JVM операция записи/обновления ссылки(адреса) в памяти для элементов(в ArrayList) и для  value(в Map) атомарна и поток не может быть вытеснен начав её обновлять/записывать и не закончив ? Объясните, пожалуйста...
Сам, вот уже сажусь за Дуга Ли, но там 400 стр и на английском, не знаю как скоро освою. 


Это сообщение отредактировал(а) novichiok - 20.10.2011, 14:00
PM MAIL   Вверх
priam220
Дата 19.10.2011, 16:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Цитата

операцию set() синхронизировать не нужно

по идее нет, во всяком случае ConcurrentModificationException  вываливаться не должно, насколько я понимаю. Но если скажем вы работаете со сложным объектом. Один поток читает его, а второй изменяет. В результате целостность объекта может быть нарушена.  

PM MAIL   Вверх
Skipy
Дата 19.10.2011, 17:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

Репутация: 6
Всего: 16



Цитата(novichiok @ 16.10.2011,  14:45)
то есть, как я понимаю, операцию set() синхронизировать не нужно? 

то есть, как я понимаю, я могу *потокобезопасно* читать с Мапа, и кроме того !!! *потокобезопасно* модифицировать value для этого метода, при этом ничего 
не синхронизировав ?

1. Нужно. Если Вы выставляете значение ссылки в потоке 1, то в потоке 2 без синхронизации никто не гарантирует корректного чтения. Когда-то эта ссылка дойдет и до потока 2, но совершенно необязательно сразу.

2. Полностью аналогично. Вычитать Вы можете старые данные после того, как они уже поменялись. 

Это сообщение отредактировал(а) Skipy - 19.10.2011, 17:07


--------------------
С уважением,
Евгений aka Skipy
www.skipy.ru
PM MAIL WWW ICQ   Вверх
COVD
Дата 19.10.2011, 17:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


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

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



Цитата

Для чего вообще предназначена синхронизация...
В моем понимании для 2 вещей - 1) сохранение целостности данных ...2) сохранение целостности структур данных... 

На самом деле это одна вещь - сохранение целостности обьектов. И данные и коллекции данных - обьекты. В стандартные библиотечные классы (например, в упомянутые коллекции) уже включены средства контроля (типа ConcurrentModificationException), а ответственность за синхронизацию обьектов любых других классов (данные) полностью лежит на создателях этих классов, т.е. да, "это уже *мои* проблемы".
PM MAIL   Вверх
priam220
Дата 19.10.2011, 18:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Skipy,  ваши труды по потокам бесценны, сам периодами заглядываю в них (хотя вот конкретно по коллекциям там маловато). Но, тем не менее. Позвольте не согласиться по поводу категоричности "нужно".
Скажем доступ к объекту Integer. Есть два потока. Один на чтение, другой на запись. Допустим вы синхронизируете доступ к этому объекту. Поток на чтение занял монитор и не дает пишущему доступ. Прочитал и отправился отдыхать, в то время, когда записывающий поток мог бы в конкурентной борьбе забить туда данные и на этом итерация бы закончилась. 
Со сложными объектами немного будет сложнее. Может прийти частично обновленный объект, что почти всегда критично. Но и тут не обязательно синхронизировать set (а это значит List). Достаточно засинкать сам объект, который хронится в List'e. 
Синхронизация List'a будет нужна в случае добавления удаления туда\оттуда элемента. Что и сказано в документации.
Разве нет?  smile 

Это сообщение отредактировал(а) priam220 - 19.10.2011, 18:24
PM MAIL   Вверх
novichiok
Дата 20.10.2011, 13:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Цитата(Skipy @  19.10.2011,  17:06 Найти цитируемый пост)
1. Нужно. Если Вы выставляете значение ссылки в потоке 1, то в потоке 2 без синхронизации никто не гарантирует корректного чтения. Когда-то эта ссылка дойдет и до потока 2, но совершенно необязательно сразу.

2. Полностью аналогично. Вычитать Вы можете старые данные после того, как они уже поменялись. 


Ну это я и имел ввиду в своем посте. То что я не синхронизирую сеттеры для коллекции - опасно *только* для логики моей программы (читаются старые данные и тд и тп) Но в то же время JVMу абсолютно не кретично синхронизация сеттеров у коллекций, ведь JVM ничего не знает как там что у меня работает, так ведь ? 

+ еще, можете ,пожалуйста, высказаться по поводу цитат с javadoc'а ... У меня с них начало немного рушится мировозрение =) , и буду очень благодарен если более опытные люди отпишутся по этому поводу. + глянуть секцию PS из 1-го поста и мои там размышления 
Спасибо

Добавлено через 7 минут и 17 секунд
Цитата(priam220 @  19.10.2011,  16:19 Найти цитируемый пост)
по идее нет, во всяком случае ConcurrentModificationException  вываливаться не должно, насколько я понимаю. Но если скажем вы работаете со сложным объектом. Один поток читает его, а второй изменяет. В результате целостность объекта может быть нарушена. 


В этой теме я имею ввиду set() *только* коллекций в Java. Спрашиваю потому что прочитал javadoc и меня смутили цитаты, которые я привел в 1-ом посте. Понятно что для своих каких то объектов с состоянием синхронизация сеттеров нужна

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


Опытный
**


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

Репутация: 6
Всего: 16



Цитата(priam220 @ 19.10.2011,  18:21)
Со сложными объектами немного будет сложнее. Может прийти частично обновленный объект, что почти всегда критично. Но и тут не обязательно синхронизировать set (а это значит List). Достаточно засинкать сам объект, который хронится в List'e. 
Синхронизация List'a будет нужна в случае добавления удаления туда\оттуда элемента. Что и сказано в документации.
Разве нет?  smile

Нет.

Допустим у Вас есть List. В нем есть массив, в котором какие-то элементы заполнены. В одном потоке Вы меняете значение одного элемента массива через set - меняете Вы ссылку в массиве. В другом потоке после этого Вы можете получить еще старое значение (старую ссылку), поскольку объект типа List, в котором и содержится массив, Вы не синхронизировали.


--------------------
С уважением,
Евгений aka Skipy
www.skipy.ru
PM MAIL WWW ICQ   Вверх
priam220
Дата 20.10.2011, 18:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Skipy, вы рассматриваете заведомо выгодную ситуацию для синхронизации,  - синхронизированная запись, потом чтение... А если наоборот - сначало синхронизированное чтение, потом произошла запись (речь идет об асинхронных операциях)? 
К тому же засинканый List должен ощутимо замедлять работу, если потоков будет много.

PM MAIL   Вверх
novichiok
Дата 20.10.2011, 18:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Товарищи. Вопрос изначально ставился так  - "set() для коллекции не структурная операция => её можно не синхронизировать ****с точки зрения JVM****" О сохранности логических данных в этой коллекции речи не шло...
PM MAIL   Вверх
priam220
Дата 20.10.2011, 20:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Skipy, операция set должна быть синхронизирована в том случае, если List может быть спонтанно удален. Т.е. существует вероятность того, что вызов set приведет к NPE. Но это лучше решить локальной сихронизацией. Как вы считаете?  smile 
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   tux
javastic
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

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

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


 




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


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

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