Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
Форум программистов > Java: Общие вопросы > Ещё раз о volatile |
Автор: Рубильник 20.9.2018, 11:15 | ||
Есть у нас 2 класса, один ссылается на другой.
И есть у нас много потоков, которые видят экземпляр класса Master, и из него дергают метода класса Worker. Предположим, что мы гарантируем другими средствами, что методы Worker одновременно не вызываются несколькими потоками. Нужно ли ставить volatile на переменную size, или будет достаточно поставить на переменную worker? Формально переменную size читают и записывают разные потоки, значит как бы надо её делать volatile. Но тогда нужно получается делать volatile ВСЕ поля ВСЕХ внутренних классов(на которые есть зависимости). У вас есть класс, который хранит "базу данных" (список Городов-Магазинов-Продавцов-Товаров- ....), то придется вешать volatile на все эти классы? В какой момент переменная заносится в мастер копию потока? Переменная worker не меняется, и общая для потоков. Поток один выполнят worker.setSize(5); затем второй поток через 1 секунду выполняет worker.setSize(10); Опять первый поток через 2 секунды читает worker.getSize(); Есть ли возможность, что первый поток прочитает 5 из своей мастер копии, а не 10? Есть ли возможность, что оптимизатор раскроет явно инструкции класс Worker (как inline метод), и это повлияет на работу программы. |
Автор: Рубильник 20.9.2018, 11:39 | ||
Уточню свой вопрос.
Может ли случится так, что оптимизатор, увидев, что между записью и чтением в master.worker.size ничего с этими полями не происходит, решит прочитать не из объекта, а из кеша (или мастер копии)? |
Автор: Рубильник 20.9.2018, 13:40 | ||
synchronized сбрасывает кеш? Сбрасывает при входе в блок, или при выходе из блока? "на одном и том же объекте" Уточните этот момент. Если synchronized идет на разных объектах, тогда как? "будут видны потокам которые потом зайдут в этот synchronized блок" А если блоков несколько?
Будут ли изменения сделанные в методе a() одним потоком видны другому потоку в методе b()? Что же это получается: один и тот же метод, вызванный внутри блока синхронизации и вызванный просто так, будут работать по разному? Один с общей памятью, а второй с мастер-копией. Т.е. методу есть разница где его вызвали? |
Автор: LSD 20.9.2018, 16:44 | ||
1. Забудь про все эти "сбрасывать кэш", "писать напрямую в память" и прочую ересь. 2. Есть https://docs.oracle.com/javase/specs/jls/se10/html/jls-17.html#jls-17.4 которая оперирует терминами видимости изменений между разными потоками. Там это описывается посредством Happens Before - если один участок кода находится в отношении Happens Before с другим - то все изменения которые произведены в первом будут видны во втором. Как это будет реализованно - установкой memory barrier , сбросом кэшей или еще как - не оговаривается. (например в случае с одноядерной x86 машиной, JVM вообще ничего не нужно делать) 3. Конкретно про synchronized - говориться что освобождение монитора Happens Before захвата этого же монитора другим тредом. Для разных мониторов такой гарантии - нет. |