Форум программистов, компьютерный форум, киберфорум
Наши страницы
Java SE (J2SE)
Войти
Регистрация
Восстановить пароль
 
Bakuard
0 / 0 / 1
Регистрация: 25.12.2016
Сообщений: 75
#1

Синхронизация рабочей памяти потоков и volatile - Java SE

22.01.2017, 16:29. Просмотров 227. Ответов 6
Метки нет (Все метки)

Доброго времени суток.

Пытаюсь разобраться с модификатором volatile. Как мне кажется, что-то я понял, но не уверен до конца. Пожалуйста, поправьте где ошибся.

http://www.cyberforum.ru/java-j2se/thread200073.html
1. Каждые чтение и запись переменной, помеченной как volatile, осуществляется непосредственно в/из главной памяти и являются атомарными.
В данном выражении:

Java
1
2
3
volatile long value;
 
value = someVareable + 5 - someVareable2;
переменная value считывается из главной памяти потока в рабочую, затем в рабочей памяти целиком вычисляется всё выражение и уже потом результат обратно записывается в главную память. При этом в момент вычисления нового значения, другой поток может запросить volatile переменную из главной памяти и будет работать с устаревшим значением.

2. volatile переменная окружена data memory barrier'ом. Запись и чтение переменных, которые находятся по одну из сторон барьера, компилятор может менять местами между собой, но они не могут "переходить" через барьер.

Java
1
2
3
4
5
int x1 = 5;
int x2 = 55;
volatile int y;
int x3 = 11;
int x4 = 2;
Т.е. местами могут поменяться x1 c x2 и x3 с x4. Других вариантов нет.

3. Каждый раз, как происходит чтение volatile переменной, все переменные в рабочей памяти потока объявляются недействительными, и поток заменяет их значениями из общей памяти (включая саму volatile переменную). При каждой записи volatile переменной в общую память, туда же записываются и все переменные из локальной памяти данного потока.
Вообще, это происходит каждый раз, если два действия связаны отношением happens-before.

4. Отношение happens-before не означает "физически выполняется прежде", т.е.

Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class SomeClass {
    private static int value = 0;
    private static volatile boolean flag = false;
    
    public static void main(String[] args) {
        new Thread(new Runnable() {
            public void run(){
                if(flag) System.out.println(value);
                else System.out.println(-100);
            }
        }).start();
 
         value = 100;
         flag = true;
    }
 
}
"Запись volatile поля happens-before чтение того же самого volatile поля" не означает что дочерняя нить будет дожидаться пока главная выполнит flag = true, но это гарантирует, что если дочерняя нить прочитает значение flag ПОСЛЕ того, как главная нить выполнит flag = true, то в консоль будет выведено 100.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
22.01.2017, 16:29
Я подобрал для вас темы с готовыми решениями и ответами на вопрос Синхронизация рабочей памяти потоков и volatile (Java SE):

Синхронизация потоков
Столкнулся с непонятной проблемой.Хочу решить задачу типа два потока заполняют...

Синхронизация потоков
Начал изучать Java 8 по книге. Наткнулся на пример искусственной реализации...

Синхронизация потоков
Требуется: Выполнить приложение командной строки с двумя параметрами , один из...

Синхронизация потоков
Пытаюсь синхронизировать потоки, но не очень выходит. Какого вывода я ожидаю:...

Синхронизация потоков в Java
Если есть блок synchronyzed то в него нужно передать Object да? То есть если...

6
Bakuard
0 / 0 / 1
Регистрация: 25.12.2016
Сообщений: 75
23.01.2017, 17:56  [ТС] #2
Хотелось бы уточнить ещё одну вещь:

Java
1
2
3
4
5
6
7
8
9
10
11
private boolean flag = false;
 
private synchronized void thread1(){
    flag = true;
}
 
private void thread2() {
    while(!flag) {
        //какие-то действия.
    }
}
если поток сохранит переменную flag в локальной памяти до того как первый поток изменит её значение на true, то цикл будет выполняться бесконечно? Или всё-таки может наступить такой момент, когда на n-ой итерации второй поток решит прочитать значение этой переменной не из своей локальной памяти, а из главной?
0
turbanoff
Эксперт Java
4004 / 3739 / 738
Регистрация: 18.05.2010
Сообщений: 9,322
Записей в блоге: 11
Завершенные тесты: 1
24.01.2017, 01:57 #3
1. всё верно.

2. Барьеры - это детали реализации. Советую не заострять на них внимание сейчас. Это не самая простая тема.
В вашем примере вы объявляете поля или локальные переменные?
Цитата Сообщение от Bakuard Посмотреть сообщение
компилятор может менять местами между собой, но они не могут "переходить" через барьер
Неверно. Зависит от того, что вы делаете с volatile полем (чтение или запись) и что делаете с не-volatile полями (чтение или запись).

3. Опять - это детали реализации. JVM обязывает, чтобы поток прочитавший значение записанное в volatile увидел и другие значение. JVM/процессор может спекулировать на этом контракте, и ниакакой фактической инвалидации/записи всей памяти не будет.
Цитата Сообщение от Bakuard Посмотреть сообщение
все переменные в рабочей памяти потока
Скорее всего вы имели в виду кэш ядра, исполняющего поток.

4. вроде верно. Хотя вы не определили, что вы подразумеваете под "физически".

Добавлено через 1 минуту
Цитата Сообщение от Bakuard Посмотреть сообщение
если поток сохранит переменную flag в локальной памяти до того как первый поток изменит её значение на true, то цикл будет выполняться бесконечно? Или всё-таки может наступить такой момент, когда на n-ой итерации второй поток решит прочитать значение этой переменной не из своей локальной памяти, а из главной?
Могут быть оба варианта. Спекой не запрещено = разрешено.
1
Bakuard
0 / 0 / 1
Регистрация: 25.12.2016
Сообщений: 75
24.01.2017, 07:16  [ТС] #4
Спасибо за ответ, turbanoff.
Насчет пункта 2 - Я так понял, что если происходит запись в volatile переменную, то операции записи в другие переменные не могут меняться местами с записью в volatile переменную и "перепрыгнуть" через неё. Т.е:
(все переменные - поля, а не локальные переменные)
Java
1
2
3
4
5
int x1 = 5;
int x2 = 55;
volatile int y;
int x3 = 11;
int x4 = 2;
Местами могут поменяться операции записи в поля x1 c x2 и x3 с x4. Других вариантов нет.
При чтении из volatile переменной, операции чтения из других переменных не могут поменяться местами с чтением из volatile переменной и "перепрыгнуть" через неё.

Насчет пункта 3 - если нет фактической инвалидации/записи всей памяти, то будет хотябы инвалидация/запись всех полей объекта, к volatile полю которого мы обращаемся?
P.s. Да, под
Цитата Сообщение от turbanoff Посмотреть сообщение
все переменные в рабочей памяти потока
я имел ввиду кэш ядра.

И насчет пункта 4 - под "физически" я хотел сказать что в этом примере:

Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class SomeClass {
    private static int value = 0;
    private static volatile boolean flag = false;
    
    public static void main(String[] args) {
        new Thread(new Runnable() {
            public void run(){
                if(flag) System.out.println(value);
                else System.out.println(-100);
            }
        }).start();
 
         value = 100;
         flag = true;
    }
 
}
"Запись volatile поля happens-before чтение того же самого volatile поля" НЕ означает дочерняя нить будет остановлена и перестанет получать процессорное время до тех пор, пока главная нить не выполнит строку flag = true;

И насчет
Цитата Сообщение от turbanoff Посмотреть сообщение
Могут быть оба варианта. Спекой не запрещено = разрешено.
, т.е. вы хотели сказать, что инвалидация/запись рабочей памяти потока будет ГАРАНТИРОВАННО осуществлена только если выполняются действия связанные отношением "happens-before". В противном случае, инвалидация/запись рабочей памяти потока может случиться в любой момент, как и не случиться вообще.

Я правильно вас понял?
0
turbanoff
Эксперт Java
4004 / 3739 / 738
Регистрация: 18.05.2010
Сообщений: 9,322
Записей в блоге: 11
Завершенные тесты: 1
24.01.2017, 10:10 #5
Цитата Сообщение от Bakuard Посмотреть сообщение
Местами могут поменяться операции записи в поля x1 c x2 и x3 с x4. Других вариантов нет.
Вы как-то странно на это смотрите. Нужно рассматривать перемещение записи до или после записи/чтения volatile, а не обмен записей между собой.
Самое главное, что не может сделать JVM - перенести запись полей x3 и x4 до записи в volatile поле y. (На самом деле может, если докажет, что это безопасно)

Цитата Сообщение от Bakuard Посмотреть сообщение
инвалидация/запись рабочей памяти потока будет ГАРАНТИРОВАННО осуществлена только если выполняются действия связанные отношением "happens-before". В противном случае, инвалидация/запись рабочей памяти потока может случиться в любой момент, как и не случиться вообще.
Примерно так.
0
Bakuard
0 / 0 / 1
Регистрация: 25.12.2016
Сообщений: 75
24.01.2017, 18:27  [ТС] #6
Извините за мою непонятлевость))))

Цитата Сообщение от turbanoff Посмотреть сообщение
Самое главное, что не может сделать JVM - перенести запись полей x3 и x4 до записи в volatile поле y. (На самом деле может, если докажет, что это безопасно)
Т.е. вы хотели сказать, что запись переменных x1 и x2 не может быть позже записи volatile поля (хотя запись переменной x1 может быть позже записи переменной x2 и наоборот), а запись переменных x3 и x4 не может быть раньше записи volatile поля (хотя опят же - запись переменной x3 может быть позже записи переменной x4). Здесь я вас правильно понял?
0
turbanoff
Эксперт Java
4004 / 3739 / 738
Регистрация: 18.05.2010
Сообщений: 9,322
Записей в блоге: 11
Завершенные тесты: 1
24.01.2017, 20:05 #7
я там напутал(.

Давайте пример попроще посмотрим.
Java
1
2
int m1, m2;
volatile int v;
Основной (пишущий) поток делает следующее:
Java
1
2
3
m1 = 5;
y = 400;
m2 = 6;
Предположим, что второй поток читает переменную y и видит там 400, после чего читает m1 и m2.

Можно сделать два вывода:
1. Этот поток (прочитавший y==400) гарантированно должен прочитать 5 из m1. Из этого следует, что JVM/процессор не может переупорядочить инструкции, так что запись в m1 окажется после записи в y.
2. Так как запись в m2 была после volatile, то читатель может не увидеть, что m2 == 6. А может увидеть (через гонку). Отсюда следует, что JVM/процессор может переупорядочить инструкции так, что запись в m2 окажется до записи в y.
1
24.01.2017, 20:05
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
24.01.2017, 20:05
Привет! Вот еще темы с решениями:

Синхронизация потоков. Java
Всем доброго времени суток, нужна помощь в реализации синхронизации потоков на...

Синхронизация потоков. Простенький пример
Здравствуйте уважаемые форумчане! Прошу помощи экспертов! Дано 3 класса... ...

Синхронизация потоков wait и notify
Народ помогите понять. Делаю два анонимных внутренних класса. Суть в том что...

Синхронизация двух потоков по общему ресурсу
Темы по поиску просматривал. Не помогло. Нужно синхронизировать два потока....


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
7
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru