undefined

Применение volatile

Java Multithreading
6 уровень , 4 лекция
Открыта

— Привет, Амиго!

— Привет, Элли!

— Хочу рассказать тебе о модификаторе volatile. Знаешь, что это такое?

— Вроде что-то связанное с нитями. Не помню точно.

— Тогда слушай. Вот тебе немного технических деталей:

В компьютере есть два вида памяти – глобальная (обычная) и встроенная в процессор. Встроенная в процессор делится на регистры, затем кэш первого уровня (L1), кэш второго уровня (L2) и третьего уровня (L3).

Эти виды памяти отличаются по скорости работы. Самая быстрая и самая маленькая память – это регистры, затем идет кэш процессора (L1, L2, L3) и, наконец, глобальная память (самая медленная).

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

— А можно как-то управлять этим процессом?

— Практически никак – всю работу делает Java-машина, она очень интеллектуальная в плане оптимизации скорости работы.

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

— И что же делать?

— На этот случай разработчики Java предусмотрели специальное ключевое слово – volatile. Если есть переменная, к которой обращаются из разных нитей, ее нужно пометить модификатором volatile, чтобы Java-машина не помещала ее в кэш. Вот как это обычно выглядит:

public volatile int count = 0;

— О, вспомнил. Ты же уже про это рассказывала. Я же это уже знаю.

— Ага, знаешь. А вспомнил, только когда я рассказала.

— Э, ну забыл немного.

— Повторение – мать учения.

Вот тебе несколько новых фактов работы модификатора volatile. Модификатор volatile гарантирует только безопасное чтение/запись переменной, но не ее изменение.

— А в чем разница?

— Вот смотри. Как изменяется переменная:

Код Что происходит на самом деле: Описание
count++
register = count;

register = register+1;

count = register;
Этап 1.
Значение переменной count копируется из глобальной памяти в регистровую память процессора.

Этап 2
Внутри процессора регистровая переменная увеличивается на 1.

Этап 3
Значение переменной копируется из процессора в глобальную память.

— Ого! Так что, изменение любой переменной происходит только в процессоре?

— Ага.

— И значения копируются туда-сюда: из памяти в процессор и обратно?

— Ага.

Так вот, модификатор volatile, гарантирует, что при обращении к переменной count она будет прочитана из памяти (этап 1). А если какая-то нить захочет присвоить ей новое значение, то оно обязательно окажется в глобальной памяти (этап 3).

Но Java-машина не гарантирует, что не будет переключения нитей между этапами 1 и 3.

— Т.е. увеличение переменной на 1 – это фактически три операции?

— Да.

— И если две нити одновременно захотят исполнить count++, то они могут помешать друг другу?

— Да, вот смотри:

Нить 1 Нить 2 Результат
register1 = count;
register1++;
count = register1;
register2 = count;
register2++;
count = register2;
register1 = count;
register2 = count;
register2++;
count = register2;
register1++;
count = register1;

— Т.е. обращаться к переменной можно, а изменять рискованно все равно?

— Ну, изменять можно, только осторожно ☺

— Это как же?

— synchronized наше все.

— Ясно.

Комментарии (63)
Чтобы просмотреть все комментарии или оставить свой,
перейдите в полную версию
Матвей Ильюнов 31 уровень
12 апреля 2021
/* Комментарий удален */
Максим 31 уровень, LA
22 февраля 2021
Многопоточное программирование – это всегда испытание😂
Богдан Зінченко 37 уровень, Харьков
10 февраля 2021
Ясно.
Иван 31 уровень, Москва
23 января 2021
где-то я это уже видел...
Andrei Po 32 уровень
19 января 2021
/* Комментарий удален */
Agent Smith 37 уровень
5 декабря 2020
Тоже крайне полезно знать - Закон Амдала
Quasar219 39 уровень, Екатеринбург
10 июля 2020
Иван Головач очень толково про эти все кэши процессора рассказал: https://www.youtube.com/watch?v=l7OnmXQiJuM&list=PL0iArnEwOMSbCTmB7CyEX9GdN6iLerCQP
Елена Попова 40 уровень
8 июля 2020
https://www.youtube.com/watch?v=CI_rOvL-OTE Очень понятное обьяснение
Павел Павличенко 35 уровень, Львов
1 июля 2020
Похоже, что переменная с модификатором volatile - это подобие глобальной переменной (общей) для нитей приложения, в которых она может быть?
Зенур 39 уровень
25 июня 2020