Модель памяти Java описывает, как потоки в языке программирования Java взаимодействуют через память. Вместе с описанием однопоточного выполнения кода модель памяти обеспечивает семантику языка программирования Java.
Первоначальная модель памяти Java, разработанная в 1995 году, широко воспринималась как сломанная, препятствовавшая многим оптимизациям времени выполнения и не обеспечивающей достаточно надежных гарантий безопасности кода. Он был обновлен в рамках процесса сообщества Java под названием Java Specification Request 133 (JSR-133), который вступил в силу в 2004 году для Tiger (Java 5.0) . [1] [2]
Контекст
Язык программирования и платформа Java предоставляют возможности потоков . Синхронизация между потоками, как известно, сложна для разработчиков; эта трудность усугубляется тем, что приложения Java могут работать на широком диапазоне процессоров и операционных систем . Чтобы делать выводы о поведении программы, разработчики Java решили, что они должны четко определить возможное поведение всех программ Java.
На современных платформах код часто выполняется не в том порядке, в котором он был написан. Он переупорядочивается компилятором, процессором и подсистемой памяти для достижения максимальной производительности. В многопроцессорных архитектурах отдельные процессоры могут иметь свои собственные локальные кэши, которые не синхронизированы с основной памятью. Обычно нежелательно требовать, чтобы потоки оставались полностью синхронизированными друг с другом, потому что это было бы слишком дорого с точки зрения производительности. Это означает, что в любой момент времени разные потоки могут видеть разные значения для одних и тех же общих данных.
В однопоточной среде легко рассуждать о выполнении кода. Типичный подход требует, чтобы система реализовывала семантику « как если бы-последовательный» отдельно для отдельных потоков. Когда выполняется отдельный поток, будет казаться, что все действия, предпринимаемые этим потоком, происходят в том порядке, в котором они появляются в программе, даже если сами действия происходят не по порядку.
Если один поток выполняет свои инструкции не по порядку, то другой поток может увидеть тот факт, что эти инструкции были выполнены не по порядку, даже если это не повлияло на семантику первого потока. Например, рассмотрим два потока со следующими инструкциями, выполняющимися одновременно, где переменные x и y инициализируются значением 0:
Поток 1 | Поток 2 |
---|---|
х = 1; | int r1 = y; |
у = 2; | int r2 = x; |
Если перестановки не выполняются и чтение y в потоке 2 возвращает значение 2, то последующее чтение x должно возвращать значение 1, потому что запись в x была выполнена до записи в y. Однако, если две записи переупорядочены, то чтение y может вернуть значение 2, а чтение x может вернуть значение 0.
Модель памяти Java (JMM) определяет допустимое поведение многопоточных программ и, следовательно, описывает, когда такое изменение порядка возможно. Он накладывает ограничения на время выполнения на отношения между потоками и основной памятью, чтобы добиться согласованных и надежных приложений Java. Делая это, это позволяет рассуждать о выполнении кода в многопоточной среде, даже несмотря на оптимизацию, выполняемую динамическим компилятором, процессором (ами) и кешами.
Модель памяти
Для выполнения одного потока правила просты. Спецификация языка Java требует виртуальной машины Java для наблюдения внутри-нити как если бы последовательной семантики. Среда выполнения (которая в данном случае обычно относится к динамическому компилятору, процессору и подсистеме памяти) может вводить любые полезные оптимизации выполнения, если результат изолированного потока гарантированно будет точно таким же, как и он. был бы, если бы все операторы выполнялись в том порядке, в котором они встречались в программе (также называемом программным порядком). [3]
Главное предостережение заключается в том, что семантика « как если бы-последовательный» не препятствует тому, чтобы разные потоки имели разные представления данных. Модель памяти дает четкое руководство о том, какие значения разрешено возвращать при чтении данных. Основные правила подразумевают, что отдельные действия могут быть переупорядочены, если не нарушается семантика потока как если-последовательный , а действия, предполагающие обмен данными между потоками, такие как получение или снятие блокировки , гарантируют, что действия, которые происходящие до них, видны другим потокам, которые видят их эффекты. Например, все, что происходит до снятия блокировки, будет считаться упорядоченным ранее и видимым для всего, что происходит после последующего получения этой же блокировки. [4]
Математически существует частичный порядок, называемый порядком выполнения до всех действий, выполняемых программой. Порядок « происходит до» включает в себя порядок программы; если одно действие происходит перед другим в программном порядке, это будет происходить до другого в случается, перед тем порядок. Кроме того, освобождение и последующее получение блокировок образуют ребра в графе «произошло до». Чтению разрешено возвращать значение записи, если эта запись является последней записью в эту переменную перед чтением по некоторому пути в порядке «произошло до» , или если запись не упорядочена по отношению к этому чтению в произошедшем. перед заказом.
Влияние
Модель памяти Java была первой попыткой предоставить исчерпывающую модель памяти для популярного языка программирования. [5] Это было оправдано растущим распространением параллельных и параллельных систем, а также необходимостью предоставить инструменты и технологии с четкой семантикой для таких систем. С тех пор потребность в модели памяти получила более широкое признание, с аналогичной семантикой, предоставленной для таких языков, как C ++ . [6]
Смотрите также
Рекомендации
- ^ Гетц, Брайан (2004-02-24). «Исправление модели памяти Java, часть 2» (PDF) . Проверено 18 октября 2010 .
- ^ Джереми Мэнсон и Брайан Гетц (февраль 2004 г.). «JSR 133 (модель памяти Java): часто задаваемые вопросы» . Проверено 18 октября 2010 .
Модель памяти Java описывает, какое поведение допустимо в многопоточном коде и как потоки могут взаимодействовать через память. Он описывает взаимосвязь между переменными в программе и низкоуровневыми деталями хранения и извлечения их из памяти или регистров в реальной компьютерной системе. Он делает это таким образом, чтобы его можно было правильно реализовать с использованием широкого спектра оборудования и большого количества оптимизаций компилятора.
- ^ Мэнсон, Джереми. "JSR-133 FAQ" .
- ^ «JLS происходит до заказа» .
- ^ Гетц, Брайан (24 февраля 2004 г.). «Исправление модели памяти Java, часть 1» (PDF) . Проверено 17 февраля 2008 .
- ^ Бем, Ганс. «Потоки и модель памяти для C ++» . Проверено 8 августа 2014 .
Внешние ссылки
- Теория и практика Java: Исправление модели памяти Java, часть 1 - статья, описывающая проблемы с исходной моделью памяти Java.
- Теория и практика Java: Исправление модели памяти Java, часть 2 - Объясняет изменения, внесенные JSR 133 в модель памяти Java.
- Прагматика модели памяти Java (стенограмма)
- Ссылки на модель памяти Java
- Внутренняя структура Java
- Веб-страница JSR-133
- JSR-133: часто задаваемые вопросы
- Руководство по внедрению JSR-133