Что такое happens before

Java Memory Model

Модель памяти Java или Java Memory Model (JMM) описывает поведение программы в многопоточной среде. Она объясняет возможное поведение потоков и то, на что должен опираться программист, разрабатывающий приложение.

В этой статье дальше приведено достаточно большое количество терминов. Думаю, что большая часть из них пригодится вам только на собеседованиях, но представлять общую картину того, что такое Java Memory Model всё-таки полезно.

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

Неправильно синхронизированные программы могут приводить к неожиданным результатам.

Thread 1Thread 2
1: r2 = A;3: r1 = B;
2: B = 1;4: A = 2;

Может показаться, что результат r2 == 2 и r1 == 1 невозможен, так как либо инструкция 1 должна быть первой, либо инструкция 3 должна быть первой. Если инструкция 1 будет первой, то она не сможет увидеть число 2, записанное в инструкции 4. Если инструкция 3 будет первой, то она не сможет увидеть результат инструкции 2.

Если какое-то выполнение программы привело бы к такому поведению, то мы бы знали, что инструкция 4 была до инструкции 1, которая была до инструкции 2, которая была до инструкции 3, которая была до инструкции 4, что совершенно абсурдно.

Однако современным компиляторам разрешено переставлять местами инструкции в обоих потоках в тех случаях, когда это не затрагивает исполнение одного потока не учитывая другие потоки. Если инструкция 1 и инструкция 2 поменяются местами, то мы с лёгкостью сможем получит результат r2 == 2 и r1 == 1.

Thread 1Thread 2
B = 1;r1 = B;
r2 = A;A = 2;

Для некоторых программистов подобное поведение может оказаться ошибочным, но здесь нужно сделать замечание, что этот код неверно синхронизирован:

Ситуация, описанные в примере выше, называется «состоянием гонки» или Data Race.

Переставлять команды может Just-In-Time компилятор или процессор. Более того, каждое ядро процессора может иметь свой кеш. А значит, у каждого процессора может быть своё значение одной и той же переменнной, что может привести к аналогичным результатам.

Модель памяти описывает, какие значения могут быть считаны в каждый момент программы. Поведение потока в изоляции должно быть таким, каким описано в самом потоке, но значения, считываемые из переменных определяются моделью памяти. Когда мы ссылаемся на это, то мы говорим, что программа подчиняется intra-thread semantic, то есть семантики однопоточного приложения.

Разделяемые переменные

Память, которая может быть совместно использована разными потоками, называется куча (shared memory или heap memory).

Все переменные экземпляров, статические поля, массивы элементов хранятся в куче. Дальше в этой статье я буду называть их всех просто переменными.

Локальные переменные, параметры конструкторов и методов, а также параметры блока catch никогда не разделяются между потоками.

Два доступа к одной переменной называются конфликтующими, если хотя бы один их доступов меняет значение переменной (другой может как менять, так и считывать текущее значение).

Действия

Inter-thread action (термин такой, не знаю, как перевести, может, межпоточное действие?) — это действие внутри одного потока, которое может повлиять или быть замечено другим потоком. Существует несколько типов inter-thread action:

Program order

Program order (лучше не переводить, чтобы не возникло путаницы) — общий порядок потока, выполняющего действия, который отражает порядок, в котором должны быть выполнены все действия с соответствии с семантикой intra-thread semantic потока.

Действия называются sequentially consistent (лучше тоже не переводить), если все действия выполняются в общем порядке, который соответствует program order, а также каждое чтение переменной видит последнее значение, записанное туда до этого в соответствии с порядком выполнения.

Если в программе нет состояния гонки, то все запуски программы будут sequentially consistent.

Synchronization order

Synchronization order (порядок синхронизации, но лучше не переводить) — общий порядок всех действий по синхронизации в выполнении программы.

Действия по синхронизации вводят связь synchronized-with (синхронизировано с):

Happens-before

Happens-before («выполняется прежде» или «произошло-до») — отношение порядка между атомарными командами. Оно означает, что вторая команда будет видеть изменения первой команды, и что первая команды выполнилась перед второй. Рекомендую ознакомиться с многопоточностью в Java, перед продолжением чтения.

Работа с final полями

Все final поля должны быть инициализированы либо конструкциями инициализации, либо внутри конструктора. Не стоит внутри конструкторов обращаться к другим потокам. Поток увидит ссылку на объект только после полной инициализации, то есть по окончании работы конструктора. Так как final полям присваивается значение только один раз, то просто не обращайтесь к другим потоком внутри конструкторов и блоков инициализации и проблем возникнуть не должно.

Однако final поля могут быть изменены через Java Reflection API, чем пользуются, например, десериализаторы. Просто не отдавайте ссылку на объект другим потокам и не читайте значение final поля до его обновления и всё будет нормально.

Word tearing

Некоторые процессоры не позволяют записывать один байт в ОЗУ, что приводит к проблеме, называемой word tearing. Представьте, что у нас есть массив байт. Один поток записывает первый байт, а второй поток пытается записать значение в рядом стоящий байт. Но если процессор не может записать один байт, а только целое машинное слово, то запись рядом стоящего байта может быть проблематичной. Если просто считать машинное слово, обновить один байт и записать обратно, то мы помешаем другому потоку.

В JVM нет проблемы word tearing. Два потока, пишущие рядом стоящие байты не должны мешать друг другу.

Источник

Модель памяти в примерах и не только

Что такое happens before. Смотреть фото Что такое happens before. Смотреть картинку Что такое happens before. Картинка про Что такое happens before. Фото Что такое happens beforeВ продолжение серии топиков под названием «фундаментальные вещи о Java, которые стоит знать, но которые многие не знают». Предыдущий топик: Бинарная совместимость в примерах и не только

Модель памяти Java — нечто, что оказывает влияние на то, как работает код любого java-разработчика. Тем не менее, довольно многие пренебрегают знанием этой важной темы, и порой наталкиваются на совершенно неожиданное поведение их приложений, которое объясняется именно особенностями устройства JMM. Возьмём для примера весьма распространённую и некорректную реализацию паттерна Double-checked locking:

Люди, пишущие подобный код, пытаются добиться улучшения производительности, избегая блокировки, если значение уже было присвоено. К сожалению, эти люди не учитывают многих факторов, в результате проявления которых может случиться зомби-апокалипсис. Под катом я расскажу теорию и приведу примеры того, как что-то может пойти не так. Кроме того, как говорили в одном индийском фильме, «Мало знать, что не так. Нужно знать, как сделать так, чтобы было так». Потому и рецепты успеха вы также сможете найти дальше.

Немножко истории

Потому в 2004 году в Java 5 появилась JSR 133, в которой были устранены недостатки первоначальной модели. О том, что получилось, мы и будем говорить.

Atomicity

Хотя многие это знают, считаю необходимым напомнить, что на некоторых платформах некоторые операции записи могут оказаться неатомарными. То есть, пока идёт запись значения одним потоком, другой поток может увидеть какое-то промежуточное состояние. За примером далеко ходить не нужно — записи тех же long и double, если они не объявлены как volatile, не обязаны быть атомарными и на многих платформах записываются в две операции: старшие и младшие 32 бита отдельно. (см. стандарт)

Visibility

В старой JMM у каждого из запущенных потоков был свой кеш (working memory), в котором хранились некоторые состояния объектов, которыми этот поток манипулировал. При некоторых условиях кеш синхронизировался с основной памятью (main memory), но тем не менее существенную часть времени значения в основной памяти и в кеше могли расходиться.

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

Важно отметить, что, в отличие от того же C++, «из воздуха» (out-of-thin-air) значения никогда не берутся: для любой переменной справедливо, что значение, наблюдаемое потоком, либо было ранее ей присвоено, либо является значением по умолчанию.

Reordering

Но и это, как говорится, ещё не всё. Если вы сделаете заказ прямо сейчас, то ваши инструкции переставят местами совершенно бесплатно! Процессоры проявляют невероятную проворность в оптимизации исполнения инструкций. В этом им также помогает компилятор и JIT. Одним из примечательных эффектов может оказаться то, что действия, выполненные одним потоком, другой поток увидит в другом порядке. Эту фразу довольно сложно понять, просто прочитав, потому приведу пример. Пусть есть такой код:

Хотя внутри одного потока об этом можно не беспокоиться, в многопоточной среде результаты операций, произведённых другими потоками, могут наблюдаться не в том порядке. Чтобы не быть голословным, я хотел добиться того, чтобы на моей машине сработал assertion, но мне это не удавалось настолько долго ( нет, я не забыл указать при запуске ключ -ea ), что, отчаявшись, я обратился с вопросом «а как же всё-таки спровоцировать reordering» к небезызвестным перформанс-инженерам. Так на мой вопрос ответил Сергей Куксенко:

На машинах с TSO (к коим относится x86) довольно сложно показать
ломающий reordering. Это можно показать на каком-нибудь ARM’е или
PowerPC. Еще можно сослаться на Альфу — процессор с самыми слабыми правилами ордеринга. Альфа — это был ночной кошмар разработчиков компиляторов и ядер операционной системы. Счастье, что он таки умер. В сети можно найти массы историй об этом.

Классический пример:
(пример аналогичен приведённому выше — прим. автора)
… на x86 будет отрабатывать корректно всегда, ибо если вы увидели
стор в «b», то увидите и стор в «a».

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

Итак, вернёмся к нашему изначальному примеру и поймём, как может его испортить reordering. Пусть наш класс Data в конструкторе выполняет какие-то не очень тривиальные вычисления и, главное, записывает какие-то значения в не final поля:

Happens-before

Определение

Пусть есть поток X и поток Y (не обязательно отличающийся от потока X). И пусть есть операции A (выполняющаяся в потоке X) и B (выполняющаяся в потоке Y).

В таком случае, A happens-before B означает, что все изменения, выполненные потоком X до момента операции A и изменения, которые повлекла эта операция, видны потоку Y в момент выполнения операции B и после выполнения этой операции.

На словах такое определение, возможно, воспринимается не очень хорошо, потому немного поясню. Начнём с самого простого случая, когда поток только один, то есть X и Y — одно и то же. Внутри одного потока, как мы уже говорили, никаких проблем нет, потому операции имеют по отношению к друг другу happens-before в соответствии с тем порядком, в котором они указаны в исходном коде (program order). Для многопоточного случая всё несколько сложнее, и тут без… картинки не разобраться. А вот и она:

Что такое happens before. Смотреть фото Что такое happens before. Смотреть картинку Что такое happens before. Картинка про Что такое happens before. Фото Что такое happens before
Здесь слева зелёным помечены те операции, которые гарантированно увидит поток Y, а красным — те, что может и не увидеть. Справа красным помечены те операции, при исполнении которых ещё могут быть не видны результаты выполнения зелёных операций слева, а зелёным — те, при исполнении которых уже всё будет видно. Важно заметить, что отношение happens-before транзитивно, то есть если A happens-before B и B happens-before C, то A happens-before C.

Операции, связанные отношением happens-before

Посмотрим теперь, что же именно за ограничения на reordering есть в JMM. Глубокое и подробное описание можно найти, например, в The JSR-133 Cookbook, я же приведу всё на несколько более поверхностном уровне и, возможно, пропущу некоторые из ограничений. Начнём с самого простого и известного: блокировок.

1. Освобождение (releasing) монитора happens-before заполучение (acquiring) того же самого монитора. Обратите внимание: именно освобождение, а не выход, то есть за безопасность при использовании wait можно не беспокоиться.

Посмотрим, как это знание поможет нам исправить наш пример. В данном случае всё очень просто: достаточно убрать внешнюю проверку и оставить синхронизацию как есть. Теперь второй поток гарантированно увидит все изменения, потому что он получит монитор только после того, как другой поток его отпустит. А так как он его не отпустит, пока всё не проинициализирует, мы увидем все изменения сразу, а не по отдельности:

2. Запись в volatile переменную happens-before чтение из той же самой переменной.

То изменение, которое мы внесли, конечно, исправляет некорректность, но возвращает того, кто написал изначальный код, туда, откуда он пришёл — к блокировке каждый раз. Спасти может ключевое слово volatile. Фактически, рассматриваемое утверждение (2) значит, что при чтении всего, что объявлено volatile, мы всегда будем получать актуальное значение. Кроме того, как я говорил раньше, для volatile полей запись всегда (в т.ч. long и double) является атомарной операцией. Ещё один важный момент: если у вас есть volatile сущность, имеющая ссылки на другие сущности (например, массив, List или какой-нибудь ещё класс), то всегда «свежей» будет только ссылка на саму сущность, но не на всё, в неё входящее.

Итак, обратно к нашим Double-locking баранам. С использованием volatile исправить ситуацию можно так:

Кроме того, тут используется интересное предположение, которое стоит проверить: volatile store + read быстрее, чем блокировка. Однако, как неустанно повторяют нам всё те же инженеры производительности, микробенчмарки имеют мало отношения с реальностью, особенно если вы не знаете, как устроено то, что вы пытаетесь измерить. Более того, если вы думаете, что знаете, как оно устроено, то вы, скорее всего, ошибаетесь и не учитываете какие-нибудь важные факторы. У меня нет достаточной уверенности в глубине своих познаний, чтобы производить свои бенчмарки, поэтому таких замеров тут не будет. Впрочем, некоторая информация по производительности volatile есть в этой презентации начиная со слайда #54 (хотя я настойчиво рекомендую прочитать всё). UPD: есть интересный комментарий, в котором говорят, что volatile существенно быстрее синхронизации, by design.

Только в том-то и соль, что заработает оно именно магически, и человек, который не знает о вашем хитроумном приёме, может вас не понять. Да и вы тоже можете о таком довольно быстро позабыть. Есть, конечно же, вариант добавить горделивый комментарий типа «neat trick here!», описывающий, что же тут происходит, но мне это почему-то кажется не очень хорошей практикой.

UPD: Это неправда. В комментариях описано, почему. UPD2: По результатам обсуждения вопроса Руслан написал статью.

Кроме того, важно помнить, что поля бывают ещё и статические, а что инициализацию классов JVM гарантированно выполняет лишь один раз при первом обращении. В таком случае, тот же синглетон ( не будем в рамках данной статьи называть его ни паттерном, ни антипаттерном. Статья ведь совсем не об этом 😉 ) можно реализовать вот так:

Это, конечно, не является советом к тому, как нужно реализовывать синглетон, поскольку все, читавшие Effective Java, знают, что если вы совершенно неожидано по какой-то причине вдруг зачем-то решили его написать, то лучше всего использовать enum и получить из коробки решение всех проблем и с многопоточностью, и с сериализацией, и с клонированием. UPD: По поводу того, как лучше реализовать singleton, можно почитать этот топик.

Кстати, тем, кто знает, что final-поля можно изменить через Reflection и заинтересовавшимся, как такие изменения будут видны, могу сказать вот что: «всё, кажется, будет хорошо, только непонятно, почему, и непонятно, действительно ли всё и действительно ли хорошо». Есть несколько топиков на эту тему, наиболее интерен этот. Если кто-нибудь расскажет в комментариях, как оно на самом деле, я буду крайне рад. Впрочем, если никто не расскажет, то я и сам выясню и обязательно расскажу. UPD: В комментариях рассказали.

Наверняка есть ещё какие-то операции, связанные отношением happens-before, которые я не осветил в данной статье, но они уже гораздо более специфичны, и при наличии интереса вы можете их найти сами в стандарте или где-то ещё, а затем поделиться со всеми в комментариях.

Credits, links and stuff

В первую очередь хотелось бы поблагодарить за некоторые консультации и предварительную проверку статьи на содержание клинического бреда упомянутых ранее инженеров производительности: Алексея TheShade Шипилёва и Сергея Walrus Куксенко.

Источник

Русские Блоги

Из одиночного режима в Happens-Before

Эта статья в основном начинается с простого одноэлементного режима, анализирует некоторые возможные проблемы в одноэлементном режиме и как использовать Happens-Before для анализа и проверки безопасности кода в многопоточной среде.

Подготовка знаний

Для удобства нижеследующего описания и потребностей читателей в понимании статьи сначала объясните используемые точки знаний и связанные концепции.

Семантика, которая отображается как серийная в потоке

Within Thread As-If-Serial Semantics

определение

Обычные переменные гарантируют только то, что во время выполнения методаВсе места, которые зависят от результата задания, могут получить правильный результат, И не может гарантировать, что последовательность операций присваивания переменных согласуется с последовательностью выполнения в программном коде.

Дайте немного каштана

Изменение порядка

определение

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

явление

Справка Семантика, которая отображается как серийная в потоке Маленькие каштаны, выращенные в секции.

Обратите внимание, что переупорядочение инструкций может происходить в любом коде, независимо от того, является ли он многопоточным. Я не чувствую этого в одном потоке, потому что есть ограничение семантики серийного номера в потоке.

Произойдет-раньше (случится-раньше)

Что случилось раньше

Принцип «происходит до»Он должен судить, есть ли конкуренция в данных и безопасен ли поток.в основном согласно

Для удобства описания, если вы оперируете X Happens-Before и оперируете Y, мы запишем это как hb (X, Y).

Если есть hb (a, b), операции (такие как операции присваивания и т. Д.), Которые операция a выполняет в памяти, видны операции b, то есть операции a оказать влияние Операция b.

Здесь я повторяю роль Happens-Before: если есть hb (a, b), то операции (такие как операции присваивания и т. Д.), Выполняемые с памятью операцией a, видны операции b, а именно операции a оказать влияние Операция b.

Это родные отношения «Happens-Before», существующие в модели памяти Java. Они уже существуют без помощи синхронизатора и могут использоваться непосредственно при кодировании.

Эти правила хорошо понятны, поэтому я не буду их здесь подробно объяснять. Только указанные выше правила могут быть установлены на языке Java без какой-либо гарантии синхронизации.

Есть ли еще что-нибудь, что случилось раньше?

Есть только 8 приведенных выше правил, которые изначально удовлетворяют отношению Happens-Before в Java, но мы также можем использовать их для получения других операций, которые удовлетворяют Happens-Before, например:

Если какое-либо из вышеперечисленных правил Happens-Before не существует между двумя операциями, и оно не может быть вытолкнуто через существующее отношение Happens-Before, то между двумя операциями нет последовательной гарантии, виртуальная машина Вы можете изменить порядок этих двух операций!

Важная вещь повторяется трижды: если есть hb (a, b), то операции (такие как операции присваивания и т. Д.), Которые операция a выполняет с памятью, видны операции b, то есть операции a оказать влияние Операция b.

volatile

Как изменчивость гарантирует видимость

Причина проблемы видимости

Всем известно, что скорость обработки ЦП очень высока, настолько высока, что память не успевает за скоростью ЦП, и разрыв очень велик.Если это место не обрабатывается, оно обычно становится узким местом эффективности ЦП.Чтобы устранить влияние разницы в скорости, ЦП обычно Поставляется с кешем: кеш уровня 1, уровня 2 или уровня 3 (его можно увидеть в описании компьютера). JVM также выделяет рабочую память (память Woking, примечание: не основную память) каждому потоку по той же причине. Нам нужно знать, что изменения, внесенные потоками в переменные, будут отражены в рабочей памяти, а затем JVM найдет подходящее время для синхронизации изменений в рабочей памяти с основной памятью. Именно из-за разницы во времени между переменными изменения потока и синхронизацией рабочей памяти с основной памятью возникает проблема согласованности данных, которая является источником проблемы видимости.

Меры, принятые volatile

Меры, принимаемые volatile, на самом деле хорошо понятны: до тех пор, пока изменяемая volatile переменная изменяется, она немедленно синхронизируется с основной памятью. В то же время значение переменной в рабочей памяти других потоков становится недействительным и должно считываться из основной памяти при использовании. Другими словами, рабочая память потока «не кэширует» переменные, измененные volatile.

Как volatile запрещает повторный заказ

Вопрос немного сложный, нужно заметить разницу, когда есть volatile в сочетании с ассемблерным кодом. Ниже приведен пример со страницы 370 книги «Углубленное понимание виртуальной машины Java» (я хотел самостоятельно сгенерировать код сборки, но операция немного сложна):Что такое happens before. Смотреть фото Что такое happens before. Смотреть картинку Что такое happens before. Картинка про Что такое happens before. Фото Что такое happens beforeИнструкция блокировки, отмеченная красным на рисунке, появляется только тогда, когда она модифицируется с помощью volatile. Что касается ее функции, книга объясняет ее следующим образом: Эта операция эквивалентна барьеру памяти (Memory Barrier). Последующие инструкции не могут быть переупорядочены в памяти во время переупорядочения. Положение перед барьером), когда только один ЦП обращается к памяти, барьер памяти не требуется; но если два или более ЦП обращаются к одной и той же памяти и один из них наблюдает за другим, барьер памяти необходим для обеспечения согласованности Вверх. Повторюсь: переупорядочение инструкций может произойти в любое время, независимо от того, многопоточное оно или нет. Причина, по которой переупорядочение не происходит в одном потоке, заключается в том, что Семантика, которая отображается как серийная в потоке Присутствие.

Анализируйте блокировку двойного обнаружения (DCL)

Эй, после столь долгого разговора я наконец добрался до Двойного Контрольного Замка (DCL), и я устал. Всем не терпится прочитать это, ммм, я не могу дождаться, чтобы это записать.

Хотя 99% Java-программистов знают, что DCL неправильный, если их просят ответить на некоторые вопросы, почему DCL неправильный? Есть ли способ исправить? Правильный ли этот метод исправления? Если нет, то почему? На такие вопросы они смотрели на потерю, или, возможно, отвечали, или были очень уверены, но не понимали первопричину.

Я думаю, что это правильно. Я помню, когда я изучал синглтон-модель год назад, я не понимал, почему было добавлено ключевое слово volatile. Я просто следил за вами, чтобы проанализировать его. На самом деле, я не знал причины в то время. Я считаю, что многие программисты тоже были моим менталитетом в то время. (Насмешливо

Для удобства описания сначала поместите сюда образец кода DCL, который позже будет использован при анализе.

Изучение DCL с точки зрения изменчивости

Если метод получения экземпляра изменен с помощью synchronized

Похожа ли ситуация на приведенный выше пример переупорядочения? Да, если нет изменчивой модификации, эти операции можно изменить! JVM может сделать это:

Кажется, что нет проблем с одним потоком, тогда мы рассмотрим проблему в многопоточной ситуации (в сочетании с приведенным выше примером кода DCL): предположим, что есть два потока: T1, T2, в текущий момент T1 выполняется для оператора 1, а T2 выполняется для Заявление 4, может произойти следующая последовательность выполнения:

Это процесс, почему ошибки не добавляют изменчивой модификации. В настоящее время у некоторых студентов могут возникнуть вопросы.Разумно, что я не добавляю volatile, и другие потоки не должны видеть только что выполненную модификацию (операцию присваивания). Если студенты так думают, я полагаю, это, должно быть, сейчас всех сбило с толку: разве изменения, сделанные потоками, не должны быть видны другим потокам? Это должно быть видно, это должно быть видно. А volatile только гарантирует видимость, даже без нее видимость все еще существует (не гарантируется, что она будет видна).

Если вы не понимаете роль volatile в DCL, легко пропустить volatile. Вот что я нашел в энциклопедии Baidu, когда проверил информацию:Что такое happens before. Смотреть фото Что такое happens before. Смотреть картинку Что такое happens before. Картинка про Что такое happens before. Фото Что такое happens before

Я добавил это позже:

Что такое happens before. Смотреть фото Что такое happens before. Смотреть картинку Что такое happens before. Картинка про Что такое happens before. Фото Что такое happens before

Используйте Happens-Before для анализа DCL

После предыдущих приготовлений я наконец подошел ко второй теме этого блога: использованию Happens-Before для анализа DCL.

Позволь мне привести пример

Влияние volatile на Happens-Before

А теперь проанализируем, чем отличается DCL от энергозависимой модификации? Наиболее значительным изменением является отношение «Произойдет до начала», внесенное в переменную (экземпляр)! Пожалуйста, обратитесь к третьему правилу Happens-Before: Volatile Variable Rule, операции записи изменчивой переменной и операции чтения этой переменной после Happens-Before. Здесь «позади» относится ко времени. Приоритет.

подводить итоги

Эта статья разделена на две части.

первая часть

Представлены эти точки знаний и связанные с ними концепции:

Вторая часть

С помощью двух точек зрения (изменчивый, происходит до) для анализа блокировки двойного обнаружения (DCL), проанализируйте, почему возникают проблемы безопасности потоков без изменчивости:

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *