Многопоточное программирование в Java. Тимур Машнин
Чтение книги онлайн.
Читать онлайн книгу Многопоточное программирование в Java - Тимур Машнин страница 6
Это означает, что изменения в volatile переменной всегда видны для других потоков.
Опять же речь идет только об операциях чтения и записи.
Резюмируя, объявление блока кода синхронным обеспечивает для кода атомарность и видимость.
Атомарность значит, что только один поток одновременно может выполнять код, защищенный данным объектом-монитором (блокировкой), позволяя предотвратить многочисленные потоки от столкновений друг с другом во время обновления общего состояния.
Видимость связана с особенностями кэширования памяти и оптимизацией программы в процессе компилирования.
Обычно потоки могут свободно кэшировать значения для переменных так, чтобы они не обязательно сразу же были бы видны другим потокам, но, если разработчик использовал синхронизацию, во время выполнения будет проверяться, что обновления переменных, выполненные одним потоком до выхода из синхронизированного блока, сразу же будут видны другому потоку, когда он будет входить в синхронизированный блок, защищенный тем же монитором (блокировкой).
Подобное правило видимости существует и для переменных volatile.
Живучесть Liveness
Теперь, давайте рассмотрим фундаментальное свойство корректности многопоточных программ, которое называется LIVENESS или живучесть.
Когда вы пишете не многопоточную, а последовательную программу, и в ней есть ошибка, вы запускаете ее, и на экране ничего не появляется.
Вы ждете, а затем выясняете, например, что у вас в коде есть бесконечный цикл.
И тогда вы исправляете ошибку.
К сожалению, в многопоточных программах есть много других способов получить этот эффект пустого экрана.
Один из них – это DEADLOCK или взаимная блокировка.
Это мы уже видели в случае операции join.
Если два потока соединяются друг с другом, они создают цикл взаимоблокировки, и по этой причине программа не завершается.
Это не бесконечный цикл в обычном понимании, это два потока, заблокированных друг от друга на неопределенный срок.
Существуют и другие способы получения взаимоблокировки.
Например, если поток T1 выполняет синхронизированную операцию на объекте A и вложенную синхронизированную операцию на объекте B, а поток T2 выполняет синхронизированную операцию на объекте B и вложенную синхронизированную операцию на объекте A, мы получаем другую форму взаимоблокировки.
Поток T1 может получить монитор объекта A одновременно с тем, что поток T2 получит монитор объекта B, а затем каждый поток будет ожидать монитора В и А соответственно неопределенный срок.
Одним из лучших способов предотвращения взаимоблокировки – это избегать