Несколько дней назад я опубликовал статью, в которойРазница между структурой памяти JVM, моделью памяти Java и объектной моделью Java. Есть много отзывов от небольших партнеров, которые надеются подробно объяснить каждую точку знаний. Модель памяти Java является самой неясной и трудной для понимания среди этих трех областей знания и требует большого количества фоновых знаний и связанных с ними знаний.
В Интернете есть много статей о модели памяти Java, а также введение в эту область знаний в таких книгах, как "Углубленное понимание виртуальной машины Java" и "Искусство параллельного программирования на Java". Однако многие до сих пор ничего не понимают после прочтения, а некоторые даже говорят, что запутались еще больше. В этой статье я представлю модель памяти Java в целом.Цель очень проста.Прочитав эту статью, вы узнаете, что такое модель памяти Java, почему существует модель памяти Java, и какие проблемы памяти Java модель решает.
В этой статье много определений и утверждений, которые автор дает после своего понимания. Я надеюсь, что читатели смогут лучше понять модель памяти Java. Конечно, если есть какие-либо предубеждения, добро пожаловать, чтобы исправить меня.
Зачем нужна модель памяти
Прежде чем представить модель памяти Java, давайте рассмотрим, что такое модель памяти компьютера, а затем посмотрим, что делает модель памяти Java на основе модели памяти компьютера. Чтобы говорить о модели памяти компьютера, мы должны поговорить о древней истории и понять, почему существует модель памяти.
Модель памяти, английское название Memory Model, он очень старый антиквариат. Это концепция, связанная с компьютерным оборудованием. Итак, позвольте мне представить вам, что он имеет отношение к оборудованию.
Согласованность процессора и кэша
Мы все должны знать, что когда компьютер выполняет программу, каждая инструкция выполняется в ЦП, и когда она выполняется, неизбежно приходится иметь дело с данными. Данные на компьютере хранятся в основной памяти, которая является физической памятью компьютера.
Вначале все было хорошо, но с развитием технологии ЦП скорость выполнения ЦП становится все быстрее и быстрее. Поскольку технология памяти не сильно изменилась, процесс чтения и записи данных из памяти и скорость выполнения ЦП будут все больше и больше отличаться, что заставит ЦП каждый раз тратить время на работу с памятью.Много времени ожидания. .
Это похоже на начинающую компанию. В начале рабочие отношения между основателями и сотрудниками были счастливыми. Однако по мере того, как способности и амбиции основателей становились все больше и больше, между основателями и сотрудниками возник разрыв, и рядовые сотрудники не успевали.По стопам генерального директора. После того, как каждый приказ начальника будет передан рядовым сотрудникам, это займет много времени из-за отсутствия понимания и способности выполнения рядовых сотрудников. Это также незримо снижает эффективность работы всей компании.
Однако, поскольку скорость чтения и записи в памяти низкая, нам не следует развивать технологию ЦП, и мы не должны допускать, чтобы память стала узким местом компьютерной обработки.
Итак, люди придумали хороший способ увеличить кеш между процессором и памятью. Все мы знаем концепцию кэширования, которая заключается в сохранении копии данных. Отличается высокой скоростью, малой памятью и дороговизной.
Затем процесс выполнения программы становится таким:
Когда программа запущена, она скопирует данные, необходимые для операции, из основной памяти в кеш ЦП, после чего ЦП сможет напрямую считывать данные из своего кеша и записывать в него данные при выполнении вычислений.После завершения операции , данные в кеше сбрасываются в основную память.
После этого в компании начали создавать менеджеров среднего звена.Менеджеры напрямую возглавляются генеральным директором.Если у лидера есть какие-то указания, они могут напрямую сказать менеджерам, а дальше они могут заниматься своими делами. Руководители несут ответственность за координацию работы подчиненных. Потому что менеджеры знают, кто они и за что они несут ответственность. Поэтому большую часть времени различные решения компании, уведомления и т. д. должны быть только доведены до сведения генерального директора и руководства.
С постоянным улучшением возможностей ЦП один уровень кеша постепенно перестает соответствовать требованиям, и постепенно появляются многоуровневые кеши.
По порядку чтения данных и степени тесной интеграции с ЦП кэш ЦП можно разделить на кэш первого уровня (L1), кэш второго уровня (L3), а некоторые высокопроизводительные ЦП также имеют кэш третьего уровня (L3).Все сохраненные данные являются частью кэша следующего уровня.
Техническая сложность и стоимость изготовления этих трех типов тайников относительно снижаются, поэтому их емкость также относительно увеличивается.
Тогда при многоуровневом кеше выполнение программы становится таким:
Когда ЦП хочет прочитать часть данных, он сначала ищет в кеше L1, если он не найден, он ищет в кеше L2, и если он все еще не находит, он ищет в кеше L3 или объем памяти.
По мере того, как компания становится все больше и больше, и боссу приходится управлять все большим и большим количеством вещей, отдел управления компании начинает реформироваться, и начинают появляться такие менеджеры, как руководители высокого, среднего и нижнего звена. Поуровневое управление.
Одноядерный ЦП содержит только набор кэшей L1, L2 и L3; если ЦП содержит несколько ядер, то есть многоядерный ЦП, каждое ядро содержит набор кэшей L1 (и даже L2), в то время как общие кэши L3 (или и L2).
Есть также много типов компаний.В некоторых компаниях есть только один большой босс, и только он имеет последнее слово. Однако в некоторых компаниях есть такие механизмы, как совместные генеральные менеджеры и партнеры.
Одноядерный процессор похож на компанию с одним начальником, и все команды исходят от него, поэтому нужна только одна команда управления.
Многоядерный ЦП похож на компанию, основанную несколькими партнерами. Затем каждый партнер должен создать набор старших менеджеров для своего непосредственного руководства. Несколько партнеров совместно используют сотрудников нижнего уровня компании.
Есть также компании, которые продолжают расти и начинают дифференцироваться в различные дочерние компании. Каждая дочерняя компания имеет несколько ЦП, и ранее не было общего ресурса друг с другом. не влияют друг на друга.
На следующем рисунке показана структура кэша для одного процессора и двух ядер.
Благодаря постоянному повышению мощности компьютеров поддерживается многопоточность. Затем возникает проблема. Давайте проанализируем влияние однопоточности и многопоточности на одноядерный и многоядерный процессор соответственно.
**Одинарная нить. **Кэш ядра процессора доступен только одному потоку. Кэш эксклюзивный, и конфликтов доступа и прочих проблем не будет.
** Одноядерный процессор, многопоточность. **Несколько потоков в процессе будут получать доступ к общим данным в процессе одновременно.После того, как ЦП загрузит определенный фрагмент памяти в кеш, когда разные потоки обращаются к одному и тому же физическому адресу, они будут сопоставлены с одним и тем же кешем расположение, так что даже если произойдет переключение потока, кеш все равно не станет недействительным. Но поскольку в любой момент времени может выполняться только один поток, нарушение доступа к кешу отсутствует.
** Многоядерный процессор, многопоточность. **Каждое ядро имеет как минимум один кэш L1. Если несколько потоков обращаются к общей памяти в процессе, и эти несколько потоков выполняются на разных ядрах, каждое ядро будет резервировать буфер общей памяти в своем собственном кэше. Поскольку несколько ядер могут быть распараллелены, несколько потоков могут одновременно записывать в свои соответствующие кэши, и данные между соответствующими кэшами могут быть разными.
Добавьте кеш между ЦП и основной памятью, который может существовать в многопоточных сценариях.проблемы с когерентностью кэша, то есть в многоядерном процессоре содержимое кеша одних и тех же данных может быть несогласованным в собственном кеше каждого ядра.
Если заказы компании выдаются серийно, то проблем нет.
Если приказы компании издаются параллельно, и эти приказы издает один и тот же генеральный директор, с этим механизмом проблем нет. Потому что у его исполнителя заказа только одна система управления.
Если заказы компании выдаются параллельно, и эти заказы выдаются несколькими партнерами, возникает проблема. Поскольку каждый партнер будет отдавать приказы только непосредственно подчиненным ему менеджерам, а базовые сотрудники, управляемые несколькими менеджерами, могут быть общими.
Например, если партнер 1 хочет уволить сотрудника а, а партнер 2 хочет повысить сотрудника а, если его снова уволят после повышения, несколько партнеров должны встретиться для решения проблемы. Каждый из двух партнеров отдавал приказы своим менеджерам. После того, как партнер 1 отдал приказ, после того как менеджер уволил сотрудника, он знает, что сотрудник был уволен. В это время менеджер 2 партнера 2 думал, что сотрудник а был на работе до того, как узнал об этом, поэтому с радостью принял заказ на повышение а от своего партнера.
Оптимизация процессора и изменение порядка инструкций
Как упоминалось выше, добавление кеша между ЦП и основной памятью будет существовать в многопоточных сценариях.проблемы с когерентностью кэша. В дополнение к этой ситуации, есть проблема с оборудованием, что также более важно. То есть, чтобы в полной мере использовать арифметический блок внутри процессора, процессор может выполнять неупорядоченную обработку входного кода. Этооптимизация процессора.
В дополнение к оптимизации и неупорядоченной обработке кода многими популярными процессорами, компиляторы многих языков программирования также будут иметь подобные оптимизации, такие как JIT-компилятор виртуальной машины Java.перестановка инструкций.
Вполне возможно, что если оптимизация процессора и компилятор изменит порядок инструкций, это может вызвать всевозможные проблемы.
Что касается корректировки организации сотрудников, если отделу кадров будет разрешено разделяться и выполнять или реорганизовывать по желанию после получения нескольких заказов, это окажет большое влияние на сотрудника и компанию.
Проблемы с параллельным программированием
Вы можете немного запутаться в концепциях, связанных с аппаратным обеспечением, упомянутых выше, но вы все равно не знаете, какое отношение это имеет к программному обеспечению. Но вы должны знать о проблемах параллельного программирования, таких как проблемы атомарности, проблемы видимости и проблемы упорядочения.
На самом деле, проблемы атомарности, проблемы видимости и проблемы упорядочения. Это абстрактно определяется людьми. Основная проблема этой абстракции — проблема когерентности кэша, проблема оптимизации процессора и проблема перестановки инструкций, упомянутая выше.
Вот краткий обзор этих трех тем, и я не буду их подробно раскрывать, заинтересованные читатели могут изучить их самостоятельно. Мы говорим, что параллельное программирование для обеспечения безопасности данных должно соответствовать следующим трем характеристикам:
атомарностьЭто означает, что в операции процессор не может быть приостановлен в середине, а затем снова запланирован, операция не может быть прервана, или выполнение завершено, или оно не выполнено.
видимостьЭто означает, что когда несколько потоков обращаются к одной и той же переменной, один поток изменяет значение переменной, а другие потоки сразу же видят измененное значение.
упорядоченностьТо есть порядок выполнения программы соответствует порядку выполнения кода.
Вы узнали,проблемы с когерентностью кэшаНа самом деле этопроблемы с видимостью. иоптимизация процессораможет привести кпроблема атомарностииз.перестановка инструкцийэто приведет кпроблема с заказом. Поэтому концепции на аппаратном уровне далее упоминаться не будут, а будут использоваться непосредственно знакомые атомарность, видимость и упорядоченность.
Какая модель памяти
Как упоминалось выше, проблема когерентности кэш-памяти и проблема переупорядочения команд, оптимизированных для процессора, вызваны постоянным обновлением аппаратного обеспечения. Итак, существует ли какой-либо механизм, который может хорошо решить вышеуказанные проблемы?
Самый простой и прямой способ — отменить технологию оптимизации процессора и процессора, упразднить кеш ЦП и позволить ЦП напрямую взаимодействовать с основной памятью. Однако это может гарантировать проблемы параллелизма при многопоточности. Тем не менее, это немного трата пищи для удушья.
Следовательно, чтобы обеспечить атомарность, видимость и упорядоченность в параллельном программировании. Есть важное понятие, а именно — модель памяти.
**Чтобы обеспечить корректность разделяемой памяти (видимость, порядок, атомарность), модель памяти определяет спецификацию поведения операций чтения и записи многопоточных программ в системе разделяемой памяти. ** Эти правила используются для регулирования операций чтения и записи в память, чтобы обеспечить правильность выполнения инструкций. Это связано с процессором, кэшем, параллелизмом и компилятором. Он решает проблемы с доступом к памяти, вызванные многоуровневым кешем ЦП, оптимизацией процессора, перестановкой инструкций и т. д., и обеспечивает согласованность, атомарность и упорядоченность в параллельных сценариях.
Модель памяти решает проблему параллелизма главным образом двумя способами:Ограничить оптимизацию процессораииспользовать барьеры памяти. В этой статье мы не будем вдаваться в основные принципы, и заинтересованные друзья могут изучить их сами.
Что такое модель памяти Java
Ранее была представлена модель памяти компьютера, которая является важной спецификацией для решения проблем параллелизма в многопоточных сценариях. Так что же такое конкретная реализация?Разные языки программирования могут иметь разные реализации.
Мы знаем, что программы Java должны запускаться на виртуальной машине Java.Модель памяти Java (JMM) — это своего рода спецификация модели памяти, которая скрывает различия в доступе к различным аппаратным средствам и операционным системам и гарантирует, что Java-программы могут обращаться к памяти на различных платформах с одинаковым эффектом, механизмом и спецификацией.
Когда речь заходит о модели памяти Java, обычно речь идет о новой модели памяти, используемой в JDK 5, которая в основном состоит изJSR-133: JavaTM Memory Model and Thread Specificationописывать. Если вы заинтересованы, обратитесь к этому документу в формате PDF (http://www.cs.umd.edu/~pugh/java/memoryModel/jsr133.pdf).
Модель памяти Java предусматривает, что все переменные хранятся в основной памяти, а каждый поток имеет свою собственную рабочую память. В рабочей памяти потока хранится копия основной памяти, копия переменных, используемых в потоке. Все операции должны быть выполняется в рабочей памяти и не может напрямую читать или записывать в основную память. Разные потоки не могут напрямую обращаться к переменным в рабочей памяти друг друга, а передача переменных между потоками требует синхронизации данных между их собственной рабочей памятью и основной памятью.
JMM воздействует на процесс синхронизации данных между рабочей памятью и основной памятью. Он определяет, как выполнять синхронизацию данных и когда выполнять синхронизацию данных.
Упомянутые здесь основная память и рабочая память могут быть просто аналогичны концепциям основной памяти и кэш-памяти в модели памяти компьютера. Следует отметить, что основная память и рабочая память не являются тем же уровнем разделения памяти, что и куча Java, стек, область методов и т. д. в структуре памяти JVM, и не могут сравниваться напрямую. В «Глубоком понимании виртуальной машины Java» считается, что если она должна едва соответствовать определению переменных, основной памяти и рабочей памяти, то основная память в основном соответствует части данных экземпляра объекта в куче Java. Рабочая память соответствует части стека виртуальной машины.
Таким образом, подводя итог, JMM — это спецификация, целью которой является устранение несогласованности данных в локальной памяти, компилятор изменит порядок инструкций кода, процессор будет выполнять код не по порядку, когда несколько потоков взаимодействуют через общую память и т. д. вызванные проблемы.
Реализация модели памяти Java
Друзья, знакомые с многопоточностью Java, знают, что в Java предусмотрен ряд ключевых слов, связанных с параллельной обработкой, напримерvolatile
,synchronized
,final
,concurren
пакет и т. д. На самом деле это некоторые ключевые слова, предоставляемые программистам моделью памяти Java после инкапсуляции базовой реализации.
При разработке многопоточного кода мы можем напрямую использоватьsynchronized
В ожидании ключевых слов для управления параллелизмом вам не нужно заботиться об оптимизации базового компилятора, согласованности кэша и других проблемах. так,В дополнение к определению набора спецификаций модель памяти Java также предоставляет ряд примитивов, которые инкапсулируют базовую реализацию для непосредственного использования разработчиками.
В этой статье не предполагается вводить использование всех ключевых слов по одному, потому что в Интернете есть много информации об использовании каждого ключевого слова. Читатели могут учиться самостоятельно. Еще один ключевой момент, который следует отметить в этой статье, заключается в том, что, как мы упоминали ранее, параллельное программирование должно решать проблемы атомарности, упорядочения и согласованности.Давайте посмотрим, как это обеспечить в Java.
атомарность
В Java для обеспечения атомарности предусмотрены две высокоуровневые инструкции байт-кода.monitorenter
иmonitorexit
. существуетПринцип реализации синхронизированногоВ статье было представлено, что соответствующие ключевые слова в Java для этих двух байт-кодовsynchronized
.
Итак, в Java вы можете использоватьsynchronized
чтобы гарантировать атомарность операций внутри методов и блоков кода.
видимость
Модель памяти Java реализована с опорой на основную память в качестве среды передачи путем синхронизации нового значения обратно в основную память после изменения переменной и обновления значения переменной из основной памяти до того, как переменная будет прочитана.
на Явеvolatile
Ключевое слово предоставляет функцию, позволяющую синхронизировать измененную им переменную в основную память сразу после изменения, а изменяемую им переменную обновлять из основной памяти перед каждым использованием. Поэтому вы можете использоватьvolatile
Для обеспечения видимости переменных во время многопоточных операций.
Кромеvolatile
, на Явеsynchronized
иfinal
Видимость также может быть достигнута с помощью двух ключевых слов. Просто реализация другая, поэтому я не буду ее здесь распространять.
упорядоченность
В Java вы можете использоватьsynchronized
иvolatile
Для обеспечения упорядоченности операций между несколькими потоками. Реализация отличается:
volatile
Ключевое слово отключает перекомпоновку инструкций.synchronized
Ключевое слово гарантирует, что одновременно разрешена только одна операция потока.
Что ж, вот краткое введение в ключевые слова, которые можно использовать для решения проблемы атомарности, видимости и упорядочения в параллельном программировании на Java. Читатель мог заметить, что кажетсяsynchronized
Ключевое слово всемогуще, оно может одновременно удовлетворять трем вышеуказанным характеристикам, чем на самом деле злоупотребляют многие люди.synchronized
причина.
ноsynchronized
Это влияет на производительность.Хотя компилятор предоставляет множество методов оптимизации блокировки, не рекомендуется злоупотреблять ими.
Суммировать
Я полагаю, что после прочтения этой статьи вы должны понять, что такое модель памяти Java, что делает модель памяти Java и что делает модель памяти Java. Что касается этих ключевых слов, связанных с моделью памяти в Java, я надеюсь, что читатели смогут продолжить углубленное изучение и написать несколько примеров, чтобы испытать это на себе.
Вы можете обратиться к двум книгам "Углубленное понимание виртуальной машины Java" и "Искусство параллельного программирования на Java".
использованная литература
кэш процессора и многопоточность
Модель памяти и когерентность кэша
Параллельное программирование — атомарность, видимость и упорядоченность