Многопоточное программирование в Java. Тимур Машнин
Чтение книги онлайн.
Читать онлайн книгу Многопоточное программирование в Java - Тимур Машнин страница 5
Когда один поток заходит внутрь блока кода, помеченного словом synchronized, то Java-машина тут же блокирует монитор объекта, который указан в круглых скобках после слова synchronized.
Больше ни один поток не сможет зайти в этот блок, пока наш поток его не покинет.
Как только наш поток выйдет из блока, помеченного synchronized, то монитор тут же автоматически освобождается и будет свободен для захвата другим потоком.
Для нестатических методов, синхронизация метода эквивалентна синхронизации тела метода с объектом this.
Для статических методов, синхронизация метода эквивалентна синхронизации тела метода с объектом Class.
Предположим, что класс имеет два поля экземпляра: c1 и c2, которые никогда не используются вместе.
Все обновления этих полей должны быть синхронизированы, но нет никаких причин препятствовать тому, чтобы обновление c1 чередовалось с обновлением c2, чтобы не создавать ненужную блокировку.
Вместо использования синхронизированных методов или использования блокировки this, мы создаем два объекта исключительно для обеспечения блокировок.
Таким образом синхронизация блоков может дать возможность из разных потоков на одном объекте вызывать разные синхронизированные блоки.
Атомарный доступ и volatile
В программировании атомарное действие – это действие, которое происходит за один раз.
Атомарное действие не может остановиться посередине: оно либо происходит полностью, либо вообще не происходит.
Никакие промежуточные результаты атомарного действия не видны, пока действие не будет завершено.
Например, оператор инкремента ++, не является атомарным действием.
Он состоит из следующих действий:
– Получить текущее значение.
– Увеличить полученное значение на 1.
– Сохранить увеличенное значение.
Поэтому очень простые выражения могут определять сложные действия, которые могут разлагаться на другие действия.
Но есть действия, которые являются атомарными:
Это чтение и запись всех переменных, ссылочных на объекты и примитивных переменных, за исключением переменных типа long и double.
Так как в Java 64-битные long и double значения рассматриваются как два 32-битных значения.
Это означает, что 64-разрядная операция записи выполняется как две отдельные 32-разрядные операции.
И это значит, что действия с long и double переменными не являются потокобезопасными.
Когда несколько потоков получают доступ к long или double значению без синхронизации, это может вызвать проблемы.
Чтобы