powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Java [игнор отключен] [закрыт для гостей] / Reordering
25 сообщений из 83, страница 2 из 4
Reordering
    #38524809
cdtyjv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
zig zuа вот в тот момент, когда процессор начал заниматься предсказаниями и выполнил одно из них "присваивает reslitReady = true", это вот предсказанное значение уже может увидеть второй поток?Теоретически - да. Как это работает на практике в конкретном процессоре - хз.
Как бы то ни было, вам, как для Java-разработчику, должно быть пофиг на то, из-за чего именно один поток видит изменения не в том порядке. Это может быть компилятор (напр. http://preshing.com/20120625/memory-ordering-at-compile-time/#out-of-thin-air), это может быть процессор, это могут быть застрявшие в store buffer значения, и т.д. Разбираться в этой кухне особого смысла нет.
Вас должен волновать сам факт того, что это возможно. Когда пишете многопоточные программы, всегда исходите из следующего предположения:
ПравилоЕсли у меня есть переменная, с которой работают несколько потоков, и один из них в нее пишет, то в отсутствие synchronized-with отношений другие потоки могут увидеть в этой переменной непредсказуемое значение.Это может быть устаревшее значение. Это может быть текущее значение. Это может быть ни то ни другое, а вообще какая-то полная хрень. Не важно. Важно то, что вы не можете на это значение полагаться.
...
Рейтинг: 0 / 0
Reordering
    #38525008
Alexey Tomin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
zig zucdtyjv,

а вот в тот момент, когда процессор начал заниматься предсказаниями и выполнил одно из них "присваивает reslitReady = true", это вот предсказанное значение уже может увидеть второй поток?

Есть два способа написания параллельных программ в java.

1. Учите JMM и строго следуете ей. Если сказано "порядок гарантируется с помощью synchronized или volatile"- значит используете.

2. Пытаетесь предсказать логику runtime-компилятора и надеетесь, что угадали верно.

Второй подход может и сэкономит пару тактов за час. Но когда стрельнёт- ошмётки мозгов долго будут соскребать со стенки.
...
Рейтинг: 0 / 0
Reordering
    #38527463
J.Serge
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
На мой взгляд reordering чуть-чуть демонизируется.
Строки и инструкции java-кода одного Thread'а при исполнении никогда физически не меняются местами, а выполняются одна за другой. Компилятор, интерпретатор, JIT-компилятор и прочие процессоры могут чутка видоизменить код, например, заменить конкатенацию строк, убрать ненужный synchronized, заменить вызов метода на inline-код или даже поменять местами команды процессора.
Но результат (после выполнения каждой инструкции) будет 100% идентичен последовательному выполнению инструкций java-кода.

По приведенной выше ссылке:
http://www.javaspecialist.ru/2011/06/java-memory-model.html ..
Тут еще важно отметить, что для выполнения операций в рамках одного потока, спецификация JVM разрешает делать только такой reordering, который приводит к абсолютно тем же результатам, если бы все операции выполнялись в порядке указанном в исходном коде с точки зрения потока, в котором этот код выполняется. Т.е. в одном потоке reordering никогда не проявляется.
..

Список операций связанных отношением happens-before:
..
В рамках одного поток любая операция happens-before любой операцией следующей за ней в исходном коде
..


И еще по другой приведенной выше ссылке:
https://blogs.oracle.com/vmrobot/entry/модель_памяти_java ..
Существует несколько основных правил для отношения 'происходит раньше':
..
в одном потоке любое действие происходит раньше любого действия, указанного в программе позже (т.е. с точки зрения потока его
действия выполняются в порядке, указанном в программе)
..


И первоисточник:
JSR-133: JavaTM Memory Model and Thread Specification..
Happens-Before Relationship:
..
Each action in a thread happens before every subsequent action in that thread
..


(И никакой out-of-order execution не повлияет на это. Это проблемы процессора. Если он отработал что-то напрасно, исходя из ложного предположения, то пусть сам и расхлебывает это: откатывается, перенакатывается - java-разработчика это не касается).

Reordering вообще вводится и рассматривается лишь как результат взаимодействия двух Thread'ов.
Reordering при выполнении строк одного Thread'а возможен только с точки зрения стороннего Thread'а - наблюдателя.
Типа наблюдатель может увидеть результат выполнение Thread'ом некой строки кода ПОСЛЕ того, как тот же наблюдатель увидит результат выполнение этим Thread'ом последующей строки кода.

И все. Чтобы избежать такого виртуального reordering'а, надо следовать приведенным уже до меня правилам. Они простые.
...
Рейтинг: 0 / 0
Reordering
    #38527511
Basil A. Sidorov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
"В этой нитке" - да. А вот если ниток больше одной и они хоть как-то взаимодействуют ...
Возможны ньюансы, в общем. И чем больше ниток с ядрами, их исполняющими - тем суровее будут ньюансы.

P.S. На моём домашнем Sempron (не X2) будет корректно работать куча кода, которая начнёт сбоить на каком-нибудь X2 или, там, Core Duo.
...
Рейтинг: 0 / 0
Reordering
    #38527538
Фотография schwa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
zig zucdtyjvпропущено...
К сожалению, это не так. Out-of-order execution это значительно более сложная вещь, чем "раз зависимы, значит не зареордерятся".

Наверное Out-of-order execution действительно крутая и очень сложная штука, но не могли бы вы на пальцах объяснить, как вот такой код может подвергнутся реордеренгу?

Код: java
1.
2.
reslit = calc();
reslitReady = reslit != null  



с учетом того, что основное правило реордеренга гласит - после реордеринга поведение программы не должно меняться.
Такого не может быть такого т.к. out-of-order execution не может нарушить data-dependency.
Хотя тут видимо вообще в термин OOOE какой-то иной смысл вкладывается т.к. всегда это было такое архитектурное решение, которое позволяло выполнять несколько инструкций, если они не требовали одного и того же функционального юнита и не имели зависимостей по данным.
...
Рейтинг: 0 / 0
Reordering
    #38527544
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Basil A. SidorovА вот если ниток больше одной и они хоть как-то взаимодействуют
ну дак, они взаимодействуют по контракту. Не абы как пришлось.
Либо критическая секция тормозит поток, либо режьте куски БЛ без взаимодействия.
Иначе теряется смысл параллельной обособленной работы потока.
...
Рейтинг: 0 / 0
Reordering
    #38527548
Фотография schwa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
J.SergeНа мой взгляд reordering чуть-чуть демонизируется.

+1 Точно подмечено.

В ситуации отсутствия гонок весь этот сферический "реордеинг" в вакууме может быть исключительно результатом операций, которые допустимы конкретной для железки с поправкам на JMM*. А когда гонки есть, то JMM никаких детерминированных сценариев выполнения не гарантирует.

Евангелие от Джеймса Гослинга 17.4.3 If a program has no data races, then all executions of the program will appear to be sequentially consistent.


* Это отягощается тем, что тестов JMM под разные классы железяк не существует наверное вообще т.к. вопрос "а не написать ли нам такое?" был поставлен лишь во второй половине в прошлого года. Так что приятного кодирования на экзотических архитектурах
...
Рейтинг: 0 / 0
Reordering
    #38527550
cdtyjv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
schwaТакого не может быть такого т.к. out-of-order execution не может нарушить data-dependency.
Хотя тут видимо вообще в термин OOOE какой-то иной смысл вкладывается т.к. всегда это было такое архитектурное решение, которое позволяло выполнять несколько инструкций, если они не требовали одного и того же функционального юнита и не имели зависимостей по данным.Да может, может. Кто вам сказал, что переставление этих строк сломает программу в однопоточном режиме? Почему мы не можем попробовать предугадать булеан из calc(), и попробовать спекулятивно пойти дальше из какого-то конкретного предположения (напр, что он вернет true), а если мы ошебемся - откатить изменения? http://en.wikipedia.org/wiki/Branch_predictor

Я уже выражал эту мысль - нет смысла рассуждать о том, может он там что-то переставить или нет. Для нас это не имеет вообще никакого значения. Ну окей, не переставил он. Зато, например, переменная reslit расшарена между потоками, а потому для консистентного изменения нужно, скажем 20 тактов, а переменной reslitReady мы владеем эксклюзивно, и можем поменять ее в кэша за 1 такт. Вы итоге результат будет таким же, как если бы там был реордеринг - мы сначала увидим второе, а уже потом первое. С точки зрения программиста разницы никакой. Вы еще учтите, что каждый новый процессор, каждая новая версия JVMки могут иметь новые навороты. Сегодня у нас один механизм когерентности кэшей, завтра другой. Сегодня JIT переставляет инструкции с опаской, а завтра его заоптимизировали под конкретную платформу, и он начал их нещадно реордерить. Нам, джавистам, на это по-хе-рам . У нас есть JMM, которая снимает эту головную.
...
Рейтинг: 0 / 0
Reordering
    #38527558
cdtyjv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
schwaВ ситуации отсутствия гонок весь этот сферический "реордеинг" в вакууме может быть исключительно результатом операций, которые допустимы конкретной для железки с поправкам на JMM*. А когда гонки есть, то JMM никаких детерминированных сценариев выполнения не гарантирует.И это так же неверный вывод. Там четко написано: не просто "will be sequentially consistent", " appear to be sequentially consistent". Не "является консистетным", а "выглядит консистетным", то есть дает предсказуемые результаты. А уж каким образом мы достигаем этих результатов - с реордерингами, или без оных, это уже дело третье.

Вы почитайте последние дискуссии в concurrency-interest. Там зубры вроде Дага и Шипилева как раз об этом писали, недавно. А именно: знаменитый JSR 133 Cookbook от Дага, где расписано, какие барьеры куда ставить, это консервативный подход . Но если, например, у вас будут какие-то глобальные эвристики, позволяющие точно знать, нужен ли в конкретном месте барьер или нет, то можно на лету решать ставить его, там или нет. Например, вот у нас запись в volatile, вроде как надо release семантику замутить. Но этот volatile нужен будет только одному другому треду, и то, когда у писателя точно переполнится store buffer, и он точно запишет это значение, а поток-читатель к тому вреени точно пройдется по своей текущей invalidate queue и точно увидит все актуальные значения. Ну и отлично, тогда мы вообще не будем туда никаких барьеров пихать, и без них сработает.
Это так, фантазия, которая возможно вообще никакого отношения к реальности не имеет, и не реализуема. Но тем не менее, она демонстрирует идею: не "является консистентным", а "выглядит консистентным", это разные вещи.
И опять таки - нам пофиг на это, у нас есть JMM.
...
Рейтинг: 0 / 0
Reordering
    #38527586
Фотография schwa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
cdtyjvschwaТакого не может быть такого т.к. out-of-order execution не может нарушить data-dependency.
Хотя тут видимо вообще в термин OOOE какой-то иной смысл вкладывается т.к. всегда это было такое архитектурное решение, которое позволяло выполнять несколько инструкций, если они не требовали одного и того же функционального юнита и не имели зависимостей по данным.Да может, может. Кто вам сказал, что переставление этих строк сломает программу в однопоточном режиме? Почему мы не можем попробовать предугадать булеан из calc(), и попробовать спекулятивно пойти дальше из какого-то конкретного предположения (напр, что он вернет true), а если мы ошебемся - откатить изменения?
Только дело в том, что в коде выше ничего не надо предугадывать. Есть значение из какого-то расчета и потом это значение используется для следующего расчета.
...
Рейтинг: 0 / 0
Reordering
    #38527597
cdtyjv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
schwaТолько дело в том, что в коде выше ничего не надо предугадывать. Есть значение из какого-то расчета и потом это значение используется для следующего расчета.Ну опять двадцать пять :-) Кто вам сказал, что не надо предугадывать? Вы это за процессор решили? В этом то и заключается speculative branch prediction, что мы можем вычислить reslitReady, не имея в руках reslit. Например, благодаря тому, что последние 1000 раз calc() возвращал true.

Но я еще раз повторю, даже жирным выделю: нет никакого смысла спорить о том, что именно там происходит в кишках. Это ничего не изменит, гарантий видимости как не было, так и нет.
...
Рейтинг: 0 / 0
Reordering
    #38527619
J.Serge
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
cdtyjvВообще, мужики, потерпите, ждать осталось не долго - скоро будет готова моя первая часть тренинга по multithreading. В эту часть войдет вся теория по JMM, synchronized, volatile, final, а так же вопросы остановки потоков. Вчера как раз весь день рисовал схемки, как кэши работают :-)

А зачем рисовать схемки, если
cdtyjv.. нет никакого смысла спорить о том, что именно там происходит в кишках. Это ничего не изменит, гарантий видимости как не было, так и нет.

Держаться больше нету сил. Тренинг будет такой же сильный, как предыдущий?
...
Рейтинг: 0 / 0
Reordering
    #38527629
rfq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
zig zu0FD,

Отлично! volatile спасет мир.
Мир, может, и спасет, а вас - нет.

Судя по всему, вы пытаетесь сделать передачу данных между потоками без использования стандартных механизмов типа BlockingThread и synchronized блоков. Это в принципе возможно, но сначала надо научится правильно пользоваться стандартными механизмами - synchronized, volatile, ReentrantLock, Atomic*, затем выучить JMM, затем то, что появится к этому времени в Java9...

А без этого бэкграунда у вас сегодня будет работать, а завтра - нет, и из проекта вы уже ушли, а пришедший вам на замену программист будет слать прокляться на вашу голову.
...
Рейтинг: 0 / 0
Reordering
    #38527630
rfq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
zig zuесть такой код

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
    //first thread  
    reslit = calc();  
    reslitReady = true;
      
    //second thread  
    if (reslitReady){  
        takeDesision(reslit);  
    }  



А это происходит циклически или одноразово? Если циклически, то второй thread должен еще сбросить reslitReady, а первый ждать этого сброса прежде чем устанавливать reslitReady второй раз.

Почему бы вам просто не использовать очередь - даже если через нее будет передаваться единственное зyачение?
...
Рейтинг: 0 / 0
Reordering
    #38527633
Фотография schwa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
cdtyjvschwaТолько дело в том, что в коде выше ничего не надо предугадывать. Есть значение из какого-то расчета и потом это значение используется для следующего расчета.Ну опять двадцать пять :-) Кто вам сказал, что не надо предугадывать? Вы это за процессор решили? В этом то и заключается speculative branch prediction, что мы можем вычислить reslitReady, не имея в руках reslit. Например, благодаря тому, что последние 1000 раз calc() возвращал true.

Но я еще раз повторю, даже жирным выделю: нет никакого смысла спорить о том, что именно там происходит в кишках. Это ничего не изменит, гарантий видимости как не было, так и нет.
При этом если знать, что код работает на каком-нибудь интелле с TLO + WC, то все будет гаратироваться хотя никаких гарантий от JMM у нас нет. Во как.
...
Рейтинг: 0 / 0
Reordering
    #38527634
Фотография schwa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
schwacdtyjvпропущено...
Ну опять двадцать пять :-) Кто вам сказал, что не надо предугадывать? Вы это за процессор решили? В этом то и заключается speculative branch prediction, что мы можем вычислить reslitReady, не имея в руках reslit. Например, благодаря тому, что последние 1000 раз calc() возвращал true.

Но я еще раз повторю, даже жирным выделю: нет никакого смысла спорить о том, что именно там происходит в кишках. Это ничего не изменит, гарантий видимости как не было, так и нет.
При этом если знать, что код работает на каком-нибудь интелле с TLO + WCСС, то все будет гаратироваться хотя никаких гарантий от JMM у нас нет. Во как.
fixed.
...
Рейтинг: 0 / 0
Reordering
    #38527638
cdtyjv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
schwaПри этом если знать, что код работает на каком-нибудь интелле с TLO + WC, то все будет гаратироваться хотя никаких гарантий от JMM у нас нет. Во как.Не знаю, что такое TLO, TSO может быть имелось ввиду? Как бы то ни было, вот код, который на моем Intel Core i5 никаких гарантий не дает, и при этом не работает:
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
public class _02_visibility implements Runnable {
    /** Переменная, чье изменение ожидает увидеть другой поток. */
    private int val;
//    private volatile int val;

    /** {@inheritDoc} */
    @Override public void run() {
        // Инкремент переменной в цикле до тех пор, пока поток не заметит изменение переменной.
        int i = 0;

        while (val == 0)
            i++;

        System.out.println("Value change observed: " + i);
    }

    /**
     * Точка входа.
     */
    public static void main(String[] args) throws Exception {
        _02_visibility test = new _02_visibility();

        // Запуск потока.
        new Thread(test).start();

        // Даем время для старта второго потока.
        Thread.sleep(100);

        // После этого изменения второй поток должен остановиться.
        test.val = 1;

        System.out.println("Value changed.");
    }
}

Почему он не останавливается? А хз. Может из-за процессора, может из-за JITа, может еще из-за чего-то. В реальных задачах мне нафиг не упало возиться с PrintAssembly, и вдуплять, что именно там произошло. Код не работает. Важно не задрачиваться из-за конкретных причин, а знать, как устранить проблему.
...
Рейтинг: 0 / 0
Reordering
    #38527752
Alexey Tomin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
J.SergeНа мой взгляд reordering чуть-чуть демонизируется.
Строки и инструкции java-кода одного Thread'а при исполнении никогда физически не меняются местами, а выполняются одна за другой.

Читайте доки.
У тебя есть две операции записи в память (два присвоения). Компилятор не переупорядочил, JIT не трогал, но процессор, уж так пришлось, запишет их из кэша в основную память другом порядке. Его право. И если еть другой поток, который исполняется на другом процессоре, то в каком порядке он увидит изменения переменных зафисит от такого количества параметров (включая состояние кэшей этого процессора), что об этом лучше не думать вообще, пока ты не понимаешь ВСЁ это.

Ещё раз- если не полного понимания микроархитектуры, процессоров, включая их взаимодействие в многопроцессорной системе - делайте строго по рекомендациям на основе JMM и не думайте более ни о чём.

Если вам приспичило заняться высокочастотным трейдингом или ещё чем- то вы должны знать точно процессор, на котором считаете, понимать всю работу кэшей и т.п. Тогда, если захотите, можете отступать от рекомендаций JMM.
...
Рейтинг: 0 / 0
Reordering
    #38527758
J.Serge
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Alexey Tomin,

спасибо за прочтение и понимание того, что я написал выше
...
Рейтинг: 0 / 0
Reordering
    #38527842
0FD
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
cdtyjvПочему он не останавливается? А хз. Может из-за процессора, может из-за JITа, может еще из-за чего-то. В реальных задачах мне нафиг не упало возиться с PrintAssembly, и вдуплять, что именно там произошло. Код не работает. Важно не задрачиваться из-за конкретных причин, а знать, как устранить проблему.

Да знаете, пробовали ведь
// private volatile int val;
если убрать комментарий, работает ведь.
cdtyjv, 15409479 тут масштабы что делает программа и процессор несколько несопоставимы, и это мягко сказано.
...
Рейтинг: 0 / 0
Reordering
    #38527913
cdtyjv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Кстати, можете помучить вот этот код:
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
import sun.misc.*;

import java.lang.reflect.*;
import java.security.*;

public class Test {
    /**
     * Main method.
     *
     * @param args Arguments, none required.
     * @throws Exception Failure.
     */
    public static void main(String[] args) throws Exception {
        final ValueHolder holder = new PlainValueHolder();

        new Thread(new Runnable() {
            @Override 
            public void run() {
                int i = 0;

                while (holder.get() == 0)
                    i++;

                System.out.println("Value change observed: " + holder.get());
            }
        }).start();

        Thread.sleep(100);

        holder.set(1);

        System.out.println("Value changed.");
    }

    /**
     * Value holder.
     */
    private static interface ValueHolder {
        /**
         * Get value.
         *
         * @return Value.
         */
        public int get();

        /**
         * Set value.
         *
         * @param val Value.
         */
        public void set(int val);
    }

    /**
     * Value holder with regular field access.
     */
    private static class PlainValueHolder implements ValueHolder {
        /** Value. */
        private int val;

        /** {@inheritDoc} */
        @Override 
        public int get() {
            return val;
        }

        /** {@inheritDoc} */
        @Override 
        public void set(int val) {
            this.val = val;
        }
    }

    /**
     * Value holder with volatile field access.
     */
    private static class VolatileValueHolder implements ValueHolder {
        /** Value. */
        private volatile int val;

        /** {@inheritDoc} */
        @Override 
        public int get() {
            return val;
        }

        /** {@inheritDoc} */
        @Override 
        public void set(int val) {
            this.val = val;
        }
    }

    /**
     * Value holder with regular field access through unsafe.
     */
    private static class PlainUnsafeValueHolder extends UnsafeValueHolder {
        /** {@inheritDoc} */
        @Override 
        public int get() {
            return unsafe().getInt(this, offset);
        }

        /** {@inheritDoc} */
        @Override 
        public void set(int val) {
            unsafe().putInt(this, offset, val);
        }
    }

    /**
     * Value holder with volatile field read through unsafe and regular field write.
     */
    private static class ReadVolatileValueHolder extends UnsafeValueHolder {
        /** {@inheritDoc} */
        @Override 
        public int get() {
            return unsafe().getIntVolatile(this, offset);
        }

        /** {@inheritDoc} */
        @Override 
        public void set(int val) {
            this.val = val;
        }
    }

    /**
     * Value holder with regular field read and volatile field write through unsafe.
     */
    private static class WriteVolatileValueHolder extends UnsafeValueHolder {
        /** {@inheritDoc} */
        @Override 
        public int get() {
            return val;
        }

        /** {@inheritDoc} */
        @Override 
        public void set(int val) {
            unsafe().putIntVolatile(this, offset, val);
        }
    }

    /**
     * Value holder with regular field read and ordered field write through unsafe.
     */
    private static class WriteOrderedValueHolder extends UnsafeValueHolder {
        /** {@inheritDoc} */
        @Override 
        public int get() {
            return val;
        }

        /** {@inheritDoc} */
        @Override 
        public void set(int val) {
            unsafe().putOrderedInt(this, offset, val);
        }
    }

    /**
     * Value holder with regular field read guarded with monitor enter and regular field write.
     */
    private static class MonitorEnterValueHolder extends UnsafeValueHolder {
        /** {@inheritDoc} */
        @Override 
        public int get() {
            unsafe().monitorEnter(this);

            return val;
        }

        /** {@inheritDoc} */
        @Override 
        public void set(int val) {
            this.val = val;
        }
    }

    /**
     * Base class for value holders using unsafe.
     */
    private abstract static class UnsafeValueHolder implements ValueHolder {
        /** Unsafe. */
        protected final Unsafe unsafe;

        /** Field offset. */
        protected final long offset;

        /** Value. */
        protected int val;

        /**
         * Constructor.
         */
        protected UnsafeValueHolder() {
            try {
                unsafe = unsafe();

                offset = unsafe.objectFieldOffset(UnsafeValueHolder.class.getDeclaredField("val"));
            }
            catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

        /**
         * Get instance of Unsafe.
         *
         * @return Instance of Unsafe.
         */
        protected Unsafe unsafe() {
            try {
                return Unsafe.getUnsafe();
            }
            catch (SecurityException ignored) {
                try {
                    return AccessController.doPrivileged
                        (new PrivilegedExceptionAction<Unsafe>() {
                            @Override
                            public Unsafe run() throws Exception {
                                Field f = Unsafe.class.getDeclaredField("theUnsafe");

                                f.setAccessible(true);

                                return (Unsafe) f.get(null);
                            }
                        });
                }
                catch (PrivilegedActionException e) {
                    throw new RuntimeException("Failed to get Unsafe.", e.getCause());
                }
            }
        }
    }
}

На моих интелах результаты такие:

PlainValueHolder - не работает;
VolatileValueHolder - работает;
PlainUnsafeValueHolder - работает;
ReadVolatileValueHolder - работает;
WriteVolatileValueHolder - не работает;
WriteOrderedValueHolder- не работает;

MonitorEnterValueHolder - работает.

Какие можно из этого сделать выводы? Обычный доступ не работает, это понятно. Чтения через acquire работают (VolatileValueHolder, ReadVolatileValueHolder, MonitorEnterValueHolder), это тоже понятно. Но вот какого хрена работает PlainUnsafeValueHolder без всяких барьеров? И почему не работает WriteVolatileValueHolder с записью с release?
Да очень просто - значит это не железяка выкобенивается, а компилятор. Когда я делаю обычное чтение через Unsafe, явно задав адрес, откуда читать - он видит апдейт. А обычные чтения апдейт не видят, так как компилятор то ли сделал себе локальную копию, то ли еще что-то. А acquire семантика убивает эту оптимизацию, тем самым позволяя нам таки увидеть изменившееся значение.

Это еще раз к тезису о том, что не так важно, понимать, почему именно программа ведет себя некорректно. Важно понимать принципы решения этих проблем.
...
Рейтинг: 0 / 0
Reordering
    #38527948
Фотография schwa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
cdtyjvschwaПри этом если знать, что код работает на каком-нибудь интелле с TLO + WC, то все будет гаратироваться хотя никаких гарантий от JMM у нас нет. Во как.Не знаю, что такое TLO, TSO может быть имелось ввиду? Как бы то ни было, вот код, который на моем Intel Core i5 никаких гарантий не дает, и при этом не работает:
Конечно такой код не работает. И если это был самый последний код, которые выполняется при завершении программы, то она бы не остановилась. А вот если он был бы расположен где-то в глубине, когда дальше будут идти запаси и обращения к "общим" локациям памяти, то все бы сработало как надо. Только это факт того, что в конкретном случае это работать будет, а не рекомендация к тому, что так делать нужно.

p.s.
TLO = Total Lock Order
...
Рейтинг: 0 / 0
Reordering
    #38527974
cdtyjv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
schwaИ если это был самый последний код, которые выполняется при завершении программы, то она бы не остановилась. А вот если он был бы расположен где-то в глубине, когда дальше будут идти запаси и обращения к "общим" локациям памяти, то все бы сработало как надо.Вы почитайте мой пост выше с анализом причин этого, и поймете, что данный код ломается независимо от "глубины".

schwaTLO = Total Lock OrderГугл такого не знает.
...
Рейтинг: 0 / 0
Reordering
    #38528036
cdtyjv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вот апдейт тестового кода, который демонстрирует, что никакая "глубина" нас не спасает:
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
252.
253.
254.
255.
256.
257.
258.
259.
260.
261.
262.
263.
264.
265.
266.
267.
268.
269.
270.
271.
272.
273.
274.
275.
276.
277.
278.
279.
280.
281.
282.
283.
284.
285.
286.
287.
288.
289.
290.
291.
292.
293.
294.
295.
296.
297.
298.
299.
300.
301.
302.
303.
304.
305.
306.
307.
308.
309.
310.
311.
312.
313.
314.
315.
316.
317.
318.
319.
320.
321.
322.
323.
324.
325.
326.
327.
328.
329.
330.
import sun.misc.*;

import java.lang.reflect.*;
import java.security.*;
import java.util.concurrent.*;

public class Test {
    /** Expected cache size. */
    private static final int CACHE_SIZE = 10 * 1024 * 1024;

    /** Expected cache line size. */
    private static final int CACHE_LINE_SIZE = 64;

    /** Amount of secondary threads. */
    private static final int THREAD_COUNT = Runtime.getRuntime().availableProcessors() * 2;

    /** Monitor. */
    private static final Object mux = new Object();

    /**
     * Main method.
     *
     * @param args Arguments, none required.
     * @throws Exception Failure.
     */
    public static void main(String[] args) throws Exception {
        final ValueHolder holder = new PlainValueHolder();

        final CacheLine[] cache = new CacheLine[CACHE_SIZE / CACHE_LINE_SIZE];

        for (int i = 0; i < CACHE_SIZE / CACHE_LINE_SIZE; i++)
            cache[i] = new CacheLine();

        new Thread(new Runnable() {
            @Override
            public void run() {
                int i = 0;

                while (holder.get() == 0)
                    i++;

                System.out.println("Value change observed: " + i);
            }
        }).start();

        Thread.sleep(100);

        final CyclicBarrier barrier = new CyclicBarrier(THREAD_COUNT);

        Thread[] threads = new Thread[THREAD_COUNT];

        for (int i = 0; i < THREAD_COUNT; i++) {
            final int idx = i + 1;

            Thread thread = new Thread(new Runnable() {
                @Override 
                public void run() {
                    synchronized (mux) {
                        holder.set(idx);
                    }

                    System.out.println("Value changed from another thread: " + idx);

                    try {
                        barrier.await();
                    }
                    catch (Exception ignore) {

                    }

                    for (CacheLine cacheLine : cache)
                        cacheLine.change();
                }
            });

            thread.start();

            threads[i] = thread;
        }

        for (Thread thread : threads)
            thread.join();

        // Iterate over all cache lines to prevent optimizations.
        long sum = 0;

        for (CacheLine line : cache)
            sum += line.sum();

        System.out.println("Iterated over cache content: " + sum);
    }

    /**
     * Cache line abstraction.
     */
    private static class CacheLine {
        /** Array. */
        private final long[] arr = new long[CACHE_LINE_SIZE / 8];

        /** Next index to change. */
        private int nextIdx;

        /**
         * Change some value in cache line.
         */
        public void change() {
            synchronized (mux) {
                for (int i = 0; i < 100 * arr.length; i++)
                    arr[nextIdx++ % arr.length]++;
            }
        }

        /**
         * Calculate cache line sum.
         *
         * @return Cache line sum.
         */
        public long sum() {
            long sum = 0;

            for (long item : arr)
                sum += item;

            return sum;
        }
    }

    /**
     * Value holder.
     */
    private static interface ValueHolder {
        /**
         * Get value.
         *
         * @return Value.
         */
        public int get();

        /**
         * Set value.
         *
         * @param val Value.
         */
        public void set(int val);
    }

    /**
     * Value holder with regular field access.
     */
    private static class PlainValueHolder implements ValueHolder {
        /** Value. */
        private int val;

        /** {@inheritDoc} */
        @Override
        public int get() {
            return val;
        }

        /** {@inheritDoc} */
        @Override
        public void set(int val) {
            this.val = val;
        }
    }

    /**
     * Value holder with volatile field access.
     */
    private static class VolatileValueHolder implements ValueHolder {
        /** Value. */
        private volatile int val;

        /** {@inheritDoc} */
        @Override
        public int get() {
            return val;
        }

        /** {@inheritDoc} */
        @Override
        public void set(int val) {
            this.val = val;
        }
    }

    /**
     * Value holder with regular field access through unsafe.
     */
    private static class PlainUnsafeValueHolder extends UnsafeValueHolder {
        /** {@inheritDoc} */
        @Override
        public int get() {
            return unsafe.getInt(this, offset);
        }

        /** {@inheritDoc} */
        @Override
        public void set(int val) {
            unsafe.putInt(this, offset, val);
        }
    }

    /**
     * Value holder with volatile field read through unsafe and regular field write.
     */
    private static class ReadVolatileValueHolder extends UnsafeValueHolder {
        /** {@inheritDoc} */
        @Override
        public int get() {
            return unsafe.getIntVolatile(this, offset);
        }

        /** {@inheritDoc} */
        @Override
        public void set(int val) {
            this.val = val;
        }
    }

    /**
     * Value holder with regular field read and volatile field write through unsafe.
     */
    private static class WriteVolatileValueHolder extends UnsafeValueHolder {
        /** {@inheritDoc} */
        @Override
        public int get() {
            return val;
        }

        /** {@inheritDoc} */
        @Override
        public void set(int val) {
            unsafe.putIntVolatile(this, offset, val);
        }
    }

    /**
     * Value holder with regular field read and ordered field write through unsafe.
     */
    private static class WriteOrderedValueHolder extends UnsafeValueHolder {
        /** {@inheritDoc} */
        @Override
        public int get() {
            return val;
        }

        /** {@inheritDoc} */
        @Override
        public void set(int val) {
            unsafe.putOrderedInt(this, offset, val);
        }
    }

    /**
     * Value holder with regular field read guarded with monitor enter and regular field write.
     */
    private static class MonitorEnterValueHolder extends UnsafeValueHolder {
        /** {@inheritDoc} */
        @Override
        public int get() {
            unsafe.monitorEnter(this);

            return val;
        }

        /** {@inheritDoc} */
        @Override
        public void set(int val) {
            this.val = val;
        }
    }

    /**
     * Base class for value holders using unsafe.
     */
    private abstract static class UnsafeValueHolder implements ValueHolder {
        /** Unsafe. */
        protected final Unsafe unsafe;

        /** Field offset. */
        protected final long offset;

        /** Value. */
        protected int val;

        /**
         * Constructor.
         */
        protected UnsafeValueHolder() {
            try {
                unsafe = unsafe();

                offset = unsafe.objectFieldOffset(UnsafeValueHolder.class.getDeclaredField("val"));
            }
            catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

        /**
         * Get instance of Unsafe.
         *
         * @return Instance of Unsafe.
         */
        private Unsafe unsafe() {
            try {
                return Unsafe.getUnsafe();
            }
            catch (SecurityException ignored) {
                try {
                    return AccessController.doPrivileged
                        (new PrivilegedExceptionAction<Unsafe>() {
                            @Override
                            public Unsafe run() throws Exception {
                                Field f = Unsafe.class.getDeclaredField("theUnsafe");

                                f.setAccessible(true);

                                return (Unsafe) f.get(null);
                            }
                        });
                }
                catch (PrivilegedActionException e) {
                    throw new RuntimeException("Failed to get Unsafe.", e.getCause());
                }
            }
        }
    }
}

И synchronized c контешном у нас там есть, и кэш мы весь гарантированно перелопатили на всех корах ... и все равно ничего не помогает.
...
Рейтинг: 0 / 0
Reordering
    #38528070
0FD
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
cdtyjv,

Это называется давай обманем jit, пусть думает что это обычная, а мы будет использовать семантику volatile и посмотрим что будет. Вот что Вы ожидаете когда определяете
protected int val;
а используете unsafe.getIntVolatile(this, offset);
...
Рейтинг: 0 / 0
25 сообщений из 83, страница 2 из 4
Форумы / Java [игнор отключен] [закрыт для гостей] / Reordering
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]