|
|
|
Java. Вопросы по многопоточности
|
|||
|---|---|---|---|
|
#18+
Добрый день, уважаемые гуру многопоточного программирование. Если Вас не затруднит, ответьте пожалуйста на несколько вопросов: 1 К примеру у меня есть какой-то объект типа Object многопоточное чтение которого происходит гораздо чаще, чем модификация и есть два варианта реализации: a) обычная переменная Object obj и ReadWriteLock соответственно на методы чтения и модификации б) volatile Object obj, на метод модификации - простой Lock, создание нового объекта и замены ссылки obj. Метод чтения без синхронизации(не считая записи-чтения volatile переменной) Какой из вариантов предпочтительнее и будет работать быстрее и почему? 2 Если я решил делать вариант 1.б и точно знаю, что мое приложение будет запускаться на сервере с несколькими процессорами архитектуры X86-64, то мог ли я вообще убрать volatile и нарушив тем самым JMM, но полагаясь на протоколы когерентности кешей процессоров? прочитает ли ядро 2го процессора измененые данные в ядре первого и даст ли это хоть какой-то прирост производительности? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 17.08.2016, 09:43 |
|
||
|
Java. Вопросы по многопоточности
|
|||
|---|---|---|---|
|
#18+
slipperyКакой из вариантов предпочтительнее и будет работать быстрее и почему? Собственно volatile один из самых дешевых способов синхронизации чтения-записи. Но, естественно, и самый примитивный. Если предполагается стратегия copy on write, то его может хватить. Если забить на то, что если два потока сделают новый клон одновременно, то отследить ситуацию, что сделанный клон происходит от заменяемого не получится. Тут уже надо что-то вроде AtomicReference. Если же надо сериализованное (или атомарное) изменение множества объектов, то следует переходить и к более сложным блокировкам. IMHO ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 17.08.2016, 09:55 |
|
||
|
Java. Вопросы по многопоточности
|
|||
|---|---|---|---|
|
#18+
2. Думать следует не столько о когерентности кешей, сколько о гранях h-b и прочих барьеров ибо если их не будет, то оптимизатор может посчитать, например, что вы занимаетесь бесполезной фигней и вообще не будет транслировать часть кода в инструкции процессору. Или сделает это не в том порядке :) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 17.08.2016, 09:59 |
|
||
|
Java. Вопросы по многопоточности
|
|||
|---|---|---|---|
|
#18+
slippery, 1 - очевидно что copy on write быстрее, он, ведь, даже не блокирует потоки 2 - превентивная оптимизация здесь ни к чему. Будет ли быстрее? Да, будет. Может ли вылезти боком? Да, может. И тут уже вам решать на сколько конкретно те несчастные наносекунды вам важнее чем риск сбоя в логике системы. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 17.08.2016, 10:44 |
|
||
|
Java. Вопросы по многопоточности
|
|||
|---|---|---|---|
|
#18+
slippery, собственно при такой постановке сложно что-либо советовать. Надо отталкиваться от алгоритма. Что ты собираешся делать с объектом. И дальше можно уже придумывать оптимизации. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 17.08.2016, 11:01 |
|
||
|
Java. Вопросы по многопоточности
|
|||
|---|---|---|---|
|
#18+
Blazkowicz 1 - очевидно что copy on write быстрее, он, ведь, даже не блокирует потоки Ну, если ради изменения 1 байта надо скопировать пару гигов, то проще подождать, пока сосед изменит свой байт. :) В отрыве от специфики, это переливание из пустого в порожнее. IMHO ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 17.08.2016, 11:07 |
|
||
|
Java. Вопросы по многопоточности
|
|||
|---|---|---|---|
|
#18+
Есть подозрение, что вы не различаете чтение/модификацию obj от чтения-модификации его полей. На x86 чтение волатила по цене примерно равно чтению обычной переменной, а запись чуть дороже записи в обычную. Так что ваш выбор - volatile. Всякие lock() нужны не потому, что они быстрее, а потому что их (в отличии от synchronized) можно отпускать не в том порядке, в котором они захватывались. (с большим риском нарваться на дедлоки, ясное дело) автор мог ли я вообще убрать volatile и нарушив тем самым JMM, но полагаясь на протоколы когерентности кешей процессоров? Тут дело не только в когерентности. Ссылка на неволатайл-обьект имеет право жить в регистре процессора некоторое время. И так же она имеет право жить где-нибудь в стеке, а коммититься в хип только иногда. На практике это означает, что если вы пишите в неволатайл-переменную - вы получите ее новое значение через какое-то случайное время. А если вы пишите в две переменных, то последовательность записи из другого потока может увидеться не той, в которой была запись. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 17.08.2016, 17:35 |
|
||
|
Java. Вопросы по многопоточности
|
|||
|---|---|---|---|
|
#18+
Т.е. в любом случае получается, что если мне в другом потоке нужно более одного _атомарного_ значение (объект), то этот объект нужно защищать synchronized. Volatile и все Atomic идут лесом ? ((( авторб) volatile Object obj, на метод модификации - простой Lock, создание нового объекта и замены ссылки obj. Метод чтения без синхронизации(не считая записи-чтения volatile переменной) Если я понимаю, так не получится ((( Т.к. при записи, не факт, что записанный объект корректно запишется в память в корректном состоянии. Т.е. запись/создание/инициализацию объекта, несмотря на то, что она как бы в одном потоке, нужно будет защищать блоком synchronized. Через volatile или AtomicReference Вы защитите ТОЛЬКО ссылку на объект, но не гарантируется консистентное состояние самого объекта IMHO & AFAIK. Надеюсь я ошибаюсь и кто нибудь меня поправит. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 17.08.2016, 19:04 |
|
||
|
Java. Вопросы по многопоточности
|
|||
|---|---|---|---|
|
#18+
Сделайте все synchronized, сэкономите время. Разницы не будет. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 17.08.2016, 22:01 |
|
||
|
Java. Вопросы по многопоточности
|
|||
|---|---|---|---|
|
#18+
chabapokЕсть подозрение, что вы не различаете чтение/модификацию obj от чтения-модификации его полей. На x86 чтение волатила по цене примерно равно чтению обычной переменной, а запись чуть дороже записи в обычную. Так что ваш выбор - volatile. Всякие lock() нужны не потому, что они быстрее, а потому что их (в отличии от synchronized) можно отпускать не в том порядке, в котором они захватывались. (с большим риском нарваться на дедлоки, ясное дело) автор мог ли я вообще убрать volatile и нарушив тем самым JMM, но полагаясь на протоколы когерентности кешей процессоров? Тут дело не только в когерентности. Ссылка на неволатайл-обьект имеет право жить в регистре процессора некоторое время. И так же она имеет право жить где-нибудь в стеке, а коммититься в хип только иногда. На практике это означает, что если вы пишите в неволатайл-переменную - вы получите ее новое значение через какое-то случайное время. А если вы пишите в две переменных, то последовательность записи из другого потока может увидеться не той, в которой была запись. локи то ты можешь снимать ставить где хочешь... НО. всё-равно бестпрактиз - это заворачивать локи в трай-кеч-файнали. а в таком раскладе разницы между синхронайзд (в контексте той темы что ты поднял) и тупо локами НЕТ. по-сути и там и тут монолитная конструкция.. конечно ты можешь тыкать локи анлоки где попало но это всего-лишь до первого эксепшена и дедлока вызванного оным. волатайл быстрее. да. (вроде был до какой то там верссии явы а потом стал как синхронайзд). НО. есть такой чудесный пакет как конкурренси, который многие моменты упрощает если придерживаться определенного стиля программирования. в контексте только чтения - во-первых, использовать что-нибудь конкуррентное, во-вторых, ридрайтлок всё-таки предпочтительнее. хотя если честно мне другое интересно )) какого характера должно быть приложение чтоб такие нюансы действительно требовались в проработке? я просто дитя веб-сервисов и сервлетконтейнеров, и там многопоточкой особо не побалуешься. вся многопоточка и конкурренси ишшуез возникают скорее на уровне бэдэ, а в приложении не то чтоб негде - даже тупо сами не рекомендуют мягко говоря, пользоваться "низкоуровневой" многопоточкой. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 17.08.2016, 23:05 |
|
||
|
Java. Вопросы по многопоточности
|
|||
|---|---|---|---|
|
#18+
Я сейчас вроде с Subj разбираюсь, но: 1. synchronized при отсутствие конфликтов вроде особо медленным не выглядит 2. При попытке сделать все на Atomic'ах, они плодятся как грибы. И уже не выглядят такими быстрыми. CPU сжирают только так. 3. На Atomic'ах нарвался на гонки между потоками. Referenc'y у меня синхронизирован, но сам экземпляр, на который он ссылается - не факт, что не лежит где-то в кешах/регистрах другого процессора. Т.е. объект с данными, к которым может быть доступ, нужно все равно оборачивать в synchronized ((( А тогда весь смысл Atomic'ов теряется. Раз synchronized в одном месте, почему бы на нем тогда все и не засинхронизировать. Гонки простейшие: один поток пишет в объект с данными, помещает его в ConcurrentLinkedQueue, второй поток берет его из ConcurrentLinkedQueue и оказывается, что данные в этом экземпляре объекта не консистентны ((( Если запись/чтение в экземпляр с данными не оборачивать synchronized. Если где ошибаюсь, поправьте. Уже дофига времени потратил, а задачу удобоваримо решить не могу ((( ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.08.2016, 01:31 |
|
||
|
Java. Вопросы по многопоточности
|
|||
|---|---|---|---|
|
#18+
Leonid KudryavtsevГонки простейшие: один поток пишет в объект с данными, помещает его в ConcurrentLinkedQueue, второй поток берет его из ConcurrentLinkedQueue и оказывается, что данные в этом экземпляре объекта не консистентны ((( Если запись/чтение в экземпляр с данными не оборачивать synchronized. Ну так ежу понятно. Для того чтобы данные были консистентными на AtomicReference надо делать CopyOnWrite. Т.е. клонировать объект его менять (ну или создавать новый) и после этого подменять ссылку на него. То, что у Вас читается консистентная ссылка, не заставляет jvm так же обрабатывать те участки памяти, на которые она ссылалась. Ей глубоко фиолетова как в стек попала ссылка из volatile, атомика или обычной переменной. Дополнительных барьеров не будет. Если же хочется править объект по живому - то нужна блокировка обращений к нему, а не только к его ссылке. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.08.2016, 08:17 |
|
||
|
Java. Вопросы по многопоточности
|
|||
|---|---|---|---|
|
#18+
slippery2 Если я решил делать вариант 1.б и точно знаю, что мое приложение будет запускаться на сервере с несколькими процессорами архитектуры X86-64, то мог ли я вообще убрать volatile и нарушив тем самым JMM, но полагаясь на протоколы когерентности кешей процессоров? прочитает ли ядро 2го процессора измененые данные в ядре первого и даст ли это хоть какой-то прирост производительности? Точно знать архитектуру железа это всего лишь малая и незначительная часть в этом вопросе. До того как до этого железа что-то вообще дойдёт ваш код будет тщательно переработан JIT причем в нескольких стадиях инлайнинга, оптимизации и компиляции, убрав volatile Вы даёте JIT карт бланш на самые жесткие оптимизации(например вынести чтение за большой цикл и положить на стек не перечитывая), и рассчитывать на то до железа оно дойдёт в том виде в каком оно написано в коде вообще не стоит, смотреть ассэмблерный код сгенерированный JIT тоже смысла нет, профиль в реальном продакшене может быть чуть-чуть другой и уже JIT сгенерирует другой машинный код. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.08.2016, 11:38 |
|
||
|
Java. Вопросы по многопоточности
|
|||
|---|---|---|---|
|
#18+
Сергей АрсеньевНу так ежу понятно. Для того чтобы данные были консистентными на AtomicReference надо делать CopyOnWrite. Т.е. клонировать объект его менять (ну или создавать новый) и после этого подменять ссылку на него. При CopyOnWrite, как я понимаю, блок который занимается CopyOnWrite нужно в synchronized оборачивать? Иначе получится тоже самое, только вид с боку. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.08.2016, 12:31 |
|
||
|
Java. Вопросы по многопоточности
|
|||
|---|---|---|---|
|
#18+
Leonid KudryavtsevТ.е. в любом случае получается, что если мне в другом потоке нужно более одного _атомарного_ значение (объект), то этот объект нужно защищать synchronized. Volatile и все Atomic идут лесом ? ((( нет, почему Код: java 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. Leonid KudryavtsevЧерез volatile или AtomicReference Вы защитите ТОЛЬКО ссылку на объект, но не гарантируется консистентное состояние самого объекта IMHO & AFAIK. Надеюсь я ошибаюсь и кто нибудь меня поправит. все там гарантируется. Сначала ставим поля объекта - потом делаем volatile write. при чтении сначала делаем volatile read - а потом читаем поля. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.08.2016, 15:19 |
|
||
|
Java. Вопросы по многопоточности
|
|||
|---|---|---|---|
|
#18+
natanabrahamjrлоки то ты можешь снимать ставить где хочешь... НО. всё-равно бестпрактиз - это заворачивать локи в трай-кеч-файнали. а в таком раскладе разницы между синхронайзд (в контексте той темы что ты поднял) и тупо локами НЕТ. по-сути и там и тут монолитная конструкция.. конечно ты можешь тыкать локи анлоки где попало но это всего-лишь до первого эксепшена и дедлока вызванного оным. ну... такой подход - это отход от БЭСТ. Но многопоточное программирование - оно такое... Вообще, лучше избегать такого, потмоу что там и без экзепшенов дедлок словить реально. но суть в том, что технически - так можно. natanabrahamjrволатайл быстрее. да. (вроде был до какой то там верссии явы а потом стал как синхронайзд). Вроде ж наоборот. Синхронизед стал в большинстве случаев быстрым почти как волатил. [/quot]во-вторых, ридрайтлок всё-таки предпочтительнее.[/quot] так говорить некорректно. Это - смотря для чего. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.08.2016, 15:32 |
|
||
|
Java. Вопросы по многопоточности
|
|||
|---|---|---|---|
|
#18+
Leonid KudryavtsevТ.е. объект с данными, к которым может быть доступ, нужно все равно оборачивать в synchronized ((( А тогда весь смысл Atomic'ов теряется. Раз synchronized в одном месте, почему бы на нем тогда все и не засинхронизировать. Гонки простейшие: один поток пишет в объект с данными, помещает его в ConcurrentLinkedQueue, второй поток берет его из ConcurrentLinkedQueue и оказывается, что данные в этом экземпляре объекта не консистентны ((( Если запись/чтение в экземпляр с данными не оборачивать synchronized. это от недопонимая jmm. посмотрите на ютубе видосы старые, там все разжевано. Скорей всего вы что-то начудили где-то. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.08.2016, 15:37 |
|
||
|
Java. Вопросы по многопоточности
|
|||
|---|---|---|---|
|
#18+
Leonid KudryavtsevПри CopyOnWrite, как я понимаю, блок который занимается CopyOnWrite нужно в synchronized оборачивать? Иначе получится тоже самое, только вид с боку. нет, ненужно - если делать правильно. Одна и та же копия данных может ложиться в кэши разных процессоров одновременно. Поэтому чтение одного объекта можно делать многопоточно. Если 10 потоков без синхронизации сделают себе локальную копию - будет 10 нормальных локальных копий. дальше поменяли поля локальной копии. и volatile write как-то так. ну или не волатил врайт - а добавить в вашу очередь. Ну или что там вам надо с ним сделать. вообще, clone - это тоже не бест практика. Лучше new. По возможности, конечно. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.08.2016, 15:45 |
|
||
|
Java. Вопросы по многопоточности
|
|||
|---|---|---|---|
|
#18+
chabapokвсе там гарантируется. Сначала ставим поля объекта - потом делаем volatile write. При copy on write. Если менять поля уже опубликованного объекта, то по барабану, волатильная ссылка или нет (она же не меняется). ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.08.2016, 16:04 |
|
||
|
Java. Вопросы по многопоточности
|
|||
|---|---|---|---|
|
#18+
Leonid KudryavtsevПри CopyOnWrite, как я понимаю, блок который занимается CopyOnWrite нужно в synchronized оборачивать? Зачем? Старый объект же не меняется. Поэтому спокойно копируем его. Меняем в копии что надо. И замещаем ссылку на новую (с проверкой, что тоже самое поменяли через AtomicReference или без оной - volatile). Другие потоки будут видеть либо ссылку на старый объект либо ссылку на новый объект после изменения ибо барьер. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.08.2016, 16:08 |
|
||
|
Java. Вопросы по многопоточности
|
|||
|---|---|---|---|
|
#18+
Конечно если у нас сложная структура объектов (типа меняем возраст человека и одновременно опечатку в имени его родителя (который ссылка на другого человека)) то тут проще будет через блокировки. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.08.2016, 16:15 |
|
||
|
Java. Вопросы по многопоточности
|
|||
|---|---|---|---|
|
#18+
Сергей АрсеньевLeonid KudryavtsevПри CopyOnWrite, как я понимаю, блок который занимается CopyOnWrite нужно в synchronized оборачивать? Зачем? Старый объект же не меняется. Поэтому спокойно копируем его. Меняем в копии что надо. И замещаем ссылку на новую (с проверкой, что тоже самое поменяли через AtomicReference или без оной - volatile). Другие потоки будут видеть либо ссылку на старый объект либо ссылку на новый объект после изменения ибо барьер. Вот тут и возникает вопрос, почему "новый объект после изменения" Изменения были в одном потоке (в кэше одного процессора), а читать объект будем в другом (другой кэш). Гонка. Сергей Арсеньевибо барьер. Кто в случае с AtomicReference сделает этот самый "барьер" на данные в объекте (не ссылка, с ней все хорошо) ? Если обернуть в synchronized...., то по концу synchronized блока все скинется в RAM. А как без synchronized ? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.08.2016, 17:29 |
|
||
|
Java. Вопросы по многопоточности
|
|||
|---|---|---|---|
|
#18+
chabapokLeonid KudryavtsevТ.е. объект с данными, к которым может быть доступ, нужно все равно оборачивать в synchronized ((( А тогда весь смысл Atomic'ов теряется. Раз synchronized в одном месте, почему бы на нем тогда все и не засинхронизировать. Гонки простейшие: один поток пишет в объект с данными, помещает его в ConcurrentLinkedQueue, второй поток берет его из ConcurrentLinkedQueue и оказывается, что данные в этом экземпляре объекта не консистентны ((( Если запись/чтение в экземпляр с данными не оборачивать synchronized. это от недопонимая jmm. посмотрите на ютубе видосы старые, там все разжевано. Скорей всего вы что-то начудили где-то. Можно более подробные ссылки. Начудили, это понятно. Тут такой самопал на самопале. Только сейчас гонку поправил. Ситуация, как описал. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.08.2016, 17:58 |
|
||
|
Java. Вопросы по многопоточности
|
|||
|---|---|---|---|
|
#18+
Leonid KudryavtsevКто в случае с AtomicReference сделает этот самый "барьер" на данные в объекте (не ссылка, с ней все хорошо) ? Если обернуть в synchronized...., то по концу synchronized блока все скинется в RAM. А как без synchronized ? Что sync, что volatile, что atomic с точки зрения JMM ставят барьер (грань happens before) и jvm должна гарантировать, что изменения сделанные в потоке A до этого барьера (записи ссылки) должны быть видны в потоке B после этого барьера (чтения ссылки). Однако, если ссылка остается прежней, а меняется содержимое, то в потоке B нельзя гарантировать, что он не прочел старое значение ссылки (то же самое) и потому барьер на него может не распространяться. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 19.08.2016, 08:06 |
|
||
|
|

start [/forum/topic.php?fid=59&msg=39294151&tid=2123800]: |
0ms |
get settings: |
9ms |
get forum list: |
13ms |
check forum access: |
3ms |
check topic access: |
3ms |
track hit: |
81ms |
get topic data: |
10ms |
get forum data: |
2ms |
get page messages: |
58ms |
get tp. blocked users: |
1ms |
| others: | 237ms |
| total: | 417ms |

| 0 / 0 |
