0 Предисловие
При параллельном программировании необходимо решить две ключевые проблемы:
- Как общаться между потоками;
- Как синхронизировать между потоками;
Связь потоков относится к механизму, с помощью которого потоки обмениваются информацией.. В императивном программировании есть два механизма связи между потоками:Общая память и передача сообщений.
В модели параллелизма с общей памятью, общее состояние программы распределяется между потоками, и потоки взаимодействуют неявно, записывая и читая общее состояние в памяти.
В параллельной модели передачи сообщений, между потоками нет общедоступного состояния, и потоки должны явно взаимодействовать, отправляя сообщения явно.
Синхронизация потоков относится к механизму, который программа использует для управления относительным порядком выполнения операций между различными потоками..
В модели параллелизма с общей памятью синхронизация выполняется явно. Программист должен явно указать, что метод или часть кода должны выполняться взаимоисключающими потоками.
В модели параллелизма передачи сообщений, поскольку сообщение должно быть отправлено до того, как сообщение будет получено., поэтому синхронизация неявна.
Параллелизм в Java использует модель разделяемой памяти.Обмен данными между потоками Java всегда является неявным, и весь процесс обмена данными полностью прозрачен для программиста.. Если вы хотите разрабатывать параллельные программы, которые работают хорошо,Очень важно понимать модель памяти Java.. Модель памяти Java диктует, как и когда можно увидеть значения общих переменных, которые были изменены другими потоками, и как при необходимости синхронизировать доступ к общим переменным.
1 Зачем нужна модель памяти
Прежде чем представить модель памяти Java, давайте рассмотрим, что такое модель памяти компьютера, а затем посмотрим, что делает модель памяти Java на основе модели памяти компьютера.. Чтобы говорить о модели памяти компьютера, мы должны поговорить о древней истории и понять, почему существует модель памяти.
1.1 Согласованность процессора и кеша
Мы все должны знать, что когда компьютер выполняет программу, каждая инструкция выполняется в процессоре, а когда она выполняется, неизбежно иметь дело с данными. Данные на компьютере хранятся в основной памяти, которая является физической памятью компьютера.
Вначале все было хорошо, но с развитием технологии ЦП скорость выполнения ЦП становится все быстрее и быстрее. И поскольку технология памяти не сильно изменилась,Следовательно, разрыв между процессом чтения и записи данных из памяти и скоростью выполнения ЦП будет становиться все больше и больше, что приведет к тому, что ЦП будет тратить много времени на ожидание каждый раз, когда он оперирует памятью..
Это как начинающая компания, в начале рабочие отношения между основателями и сотрудниками счастливы,Однако по мере роста способностей и амбиций основателей между ними и сотрудниками постепенно возник разрыв, и рядовые сотрудники стали меньше успевать за генеральным директором.. После того, как каждый приказ начальника будет передан рядовым сотрудникам, это займет много времени из-за отсутствия понимания и способности выполнения рядовых сотрудников. Это также незримо снижает эффективность работы всей компании.
Однако, поскольку скорость чтения и записи в памяти низкая, нам не следует развивать технологию ЦП, и мы не должны допускать, чтобы память стала узким местом компьютерной обработки.
Значит, люди придумали хороший способ,это увеличить кеш между процессором и памятью. Все мы знаем концепцию кэширования, которая заключается в сохранении копии данных.Характеризуется высокой скоростью, небольшим объемом памяти и дороговизной..
Затем процесс выполнения программы становится следующим:Когда программа запущена, она скопирует данные, необходимые для операции, из основной памяти в кеш ЦП, после чего ЦП сможет напрямую считывать данные из своего кеша и записывать в него данные при выполнении вычислений.После завершения операции , данные в кеше сбрасываются в основную память.
После этого в компании начали создавать менеджеров среднего звена.Менеджеры напрямую возглавляются генеральным директором.Если у лидера есть какие-то указания, они могут напрямую сказать менеджерам, а дальше они могут заниматься своими делами. Руководители несут ответственность за координацию работы подчиненных. Потому что менеджеры знают, кто они и за что они несут ответственность. Поэтому большую часть времени различные решения компании, уведомления и т. д. должны быть только доведены до сведения генерального директора и руководства.
С постоянным улучшением возможностей ЦП один уровень кеша постепенно перестает соответствовать требованиям, и постепенно появляются многоуровневые кеши.
По порядку чтения данных и степени зажатости с ЦП,Кэш ЦП можно разделить на кеш первого уровня (L1), кеш второго уровня (L3), а некоторые высокопроизводительные процессоры также имеют кеш третьего уровня (L3)., все данные, хранящиеся в кэше каждого уровня, являются частью кэша следующего уровня. Три кэшированныхТехнические трудности и производственные затраты относительно снижаются, поэтому увеличение его мощности относительно.
Тогда при многоуровневом кеше выполнение программы становится таким:Когда ЦП хочет прочитать часть данных, он сначала ищет в кеше L1, если не найден, затем ищет в кеше L2, если нет, он ищет в кеше L3 или в памяти..
По мере того, как компания становится все больше и больше, и боссу приходится управлять все большим и большим количеством вещей, отдел управления компании начинает реформироваться, и начинают появляться такие менеджеры, как руководители высокого, среднего и нижнего звена. Поуровневое управление.
Одноядерный ЦП содержит только один набор кэшей L1, L2 и L3. Если ЦП содержит несколько ядер,То есть многоядерный процессор, каждое ядро содержит набор кэшей L1 (или даже L2), при этом совместное использование кэшей L3 (или L2).
Компания также указывает на многое, в некоторых компаниях есть только один большой БОСС, и он сказал один. Однако в некоторых компаниях есть такие механизмы, как совместный генеральный директор, партнер и другие механизмы.
Одноядерный процессор похож на компанию с одним начальником, и все команды исходят от него, поэтому нужна только одна команда управления.
Многоядерный ЦП похож на компанию, основанную несколькими партнерами. Затем каждый партнер должен создать набор старших менеджеров для своего непосредственного руководства. Несколько партнеров совместно используют сотрудников нижнего уровня компании.
Есть также компании, которые продолжают расти и начинают дифференцироваться в различные дочерние компании. Каждая дочерняя компания имеет несколько ЦП, и ранее не было общего ресурса друг с другом. не влияют друг на друга.
Благодаря постоянному повышению мощности компьютеров поддерживается многопоточность. Затем возникает проблема. Давайте проанализируем влияние однопоточности и многопоточности на одноядерный и многоядерный процессор соответственно.
один поток:CPU核心的缓存只被一个线程访问。 Кэш эксклюзивный, и конфликтов доступа и прочих проблем не будет.
Одноядерный процессор, многопоточный: несколько потоков в процессе будут одновременно получать доступ к общим данным в процессе,После того, как ЦП загружает блок памяти в кеш, когда разные потоки обращаются к одному и тому же физическому адресу, они будут сопоставлены с одним и тем же расположением кеша, так что даже если произойдет переключение потока, кеш не станет недействительным.. Но поскольку в любой момент времени может выполняться только один поток, нарушение доступа к кешу отсутствует.
Многоядерный процессор, многопоточность: Каждое ядро имеет как минимум один кэш L1. Если несколько потоков обращаются к общей памяти в процессе, и эти несколько потоков выполняются на разных ядрах, каждое ядро будет резервировать буфер общей памяти в своем собственном кэше.Поскольку многоядерный может быть параллелен, ситуация может возникнуть несколько потоков одновременно записывать собственную кэширование, а данные между каждым кешем могут быть разные.
Добавьте кеш между процессором и основной памятью,В многопоточных сценариях могут возникнуть проблемы с когерентностью кеша., это,В многоядерном ЦП содержимое кеша одних и тех же данных может быть несогласованным в собственном кеше каждого ядра..
Если заказы компании выдаются серийно, то нет проблем.
Если приказы компании издаются параллельно, и эти приказы издает один и тот же генеральный директор, с этим механизмом проблем нет. Потому что у его исполнителя заказа только одна система управления.
Если заказы компании оформляются параллельно, и эти заказы оформляются несколькими партнерами, это проблема. Поскольку каждый партнер будет отдавать приказы только непосредственно подчиненным ему менеджерам, а базовые сотрудники, управляемые несколькими менеджерами, могут быть общими.
Например, если партнер 1 хочет уволить сотрудника а, а партнер 2 хочет повысить сотрудника а, если его снова уволят после повышения, несколько партнеров должны встретиться для решения проблемы. Каждый из двух партнеров отдавал приказы своим менеджерам. После того, как партнер 1 отдал приказ, после того как менеджер уволил сотрудника, он знает, что сотрудник был уволен. В это время менеджер 2 партнера 2 думал, что сотрудник а был на работе до того, как узнал об этом, поэтому с радостью принял заказ на повышение а от своего партнера.
1.2 Оптимизация процессора и изменение порядка инструкций
Как упоминалось выше, добавление кеша между ЦП и основной памятью вызовет проблемы когерентности кеша в многопоточных сценариях. В дополнение к этой ситуации, есть проблема с оборудованием, что также более важно.То есть, чтобы в полной мере использовать арифметический блок внутри процессора, процессор может выполнять неупорядоченную обработку входного кода. это оптимизация процессора.
Помимо оптимизации кода, многие языки программирования имеют подобные оптимизации.Например: мгновенный компилятор (JIT) виртуальных машин Java также будет перестроен..
Как вы можете себе представить,Все виды проблем могут возникнуть, если оптимизация процессора и переупорядочение инструкций компилятора оставлены на усмотрение..
Что касается корректировки организации сотрудников, если отделу кадров будет разрешено разделяться и выполнять или реорганизовывать по желанию после получения нескольких заказов, это окажет большое влияние на сотрудника и компанию.
1.3 Проблемы с параллельным программированием
Вы можете немного запутаться в концепциях, связанных с аппаратным обеспечением, упомянутых выше, но вы все равно не знаете, какое отношение это имеет к программному обеспечению. Но вы должны знать кое-что о параллельном программировании, например:Проблема атомарности, проблема видимости и проблема порядка.
фактически,Атомарные проблемы, проблемы видимости и проблема упорядоченности в том, что люди выходят за рамки абстрактного определения. И основная проблема этой абстракции — та, что упоминалась ранее.Проблемы когерентности кэша, проблемы с оптимизацией процессора и проблемы с изменением порядка инструкцийЖдать.Проблемы когерентности кэша на самом деле являются проблемами видимости. А оптимизация процессора может привести к проблемам с атомарностью. Перестановка заказа может вызвать проблемы с заказом.
атомарностьЭто означает, что в операции ЦП не может быть приостановлен в середине, а затем снова запланирован, операция не может быть прервана, или выполнение завершено, или оно не выполнено.
видимостьЭто означает, что когда несколько потоков обращаются к одной и той же переменной, один поток изменяет значение переменной, а другие потоки сразу же видят измененное значение.
упорядоченностьЭто означает, что порядок выполнения программы соответствует порядку выполнения кода.
2 Какая модель памяти
упоминалось ранее,Проблемы когерентности кэша и проблемы с переупорядочением инструкций, оптимизированных для процессора, вызваны постоянным обновлением оборудования.. Итак, существует ли какой-либо механизм, который может хорошо решить вышеуказанные проблемы?
Самый простой и прямой способ — отменить технологию оптимизации процессора и процессора, упразднить кеш ЦП и позволить ЦП напрямую взаимодействовать с основной памятью. Однако это может гарантировать проблемы параллелизма при многопоточности. Тем не менее, это немного трата пищи для удушья.
Следовательно, чтобы обеспечить атомарность, видимость и упорядоченность в параллельном программировании. Существует важное понятие, а именно — модель памяти, которая определяет спецификацию поведения операций чтения и записи многопоточных программ в системе с разделяемой памятью..
Эти правила используются для регулирования операций чтения и записи в память, чтобы обеспечить правильность выполнения инструкций. Это связано с процессором, кэшем, параллелизмом и компилятором. Он решает проблемы с доступом к памяти, вызванные многоуровневым кешем ЦП, оптимизацией процессора, перестановкой инструкций и т. д., и обеспечивает согласованность, атомарность и упорядоченность в параллельных сценариях.
Модель памяти решает проблемы параллелизма двумя основными способами: ограничение оптимизации процессора и использование барьеров памяти..
3 Что такое модель памяти Java
Представлен перед моделью памяти компьютера, которая является важной спецификацией для решения проблемы параллельных многопоточных сценариев.Так что же такое конкретная реализация?Разные языки программирования могут иметь разные реализации.
Мы знаем, что программы Java должны запускаться на виртуальной машине Java.Модель памяти Java (JMM) — это своего рода спецификация модели памяти, которая скрывает различия в доступе к различным аппаратным средствам и операционным системам и гарантирует, что Java-программы могут обращаться к памяти на различных платформах с одинаковым эффектом..
Модель памяти Java определяетВсе переменные хранятся в основной памяти, у каждого потока также есть своя рабочая память, рабочая память потока содержит копию основной копии памяти переменных, используемых в потоке,Все операции над переменными потоком должны выполняться в рабочей памяти и не могут напрямую читать или записывать в основную память.. Разные потоки не могут напрямую обращаться к переменным в рабочей памяти друг друга, а передача переменных между потоками требует синхронизации данных между их собственной рабочей памятью и основной памятью.
JMM воздействует на процесс синхронизации данных между рабочей памятью и основной памятью. Он указывает, как выполнять синхронизацию данных и когда выполнять синхронизацию данных..
Особо следует отметить, что,Основная память и рабочая память не являются тем же уровнем разделения памяти, что и куча Java, стек, область методов и т. д. в структуре памяти JVM, и не могут сравниваться напрямую..
Подводя итог, можно сказать, что JMM — это спецификация, которая регулирует совместную работу виртуальной машины Java и памяти компьютера.Цель состоит в том, чтобы решить проблемы, вызванные несогласованностью данных в локальной памяти, изменением порядка инструкций кода компилятором и неправильным выполнением кода процессором, когда несколько потоков взаимодействуют через общую память.. Цель состоит в том, чтобы гарантировать атомарность, видимость и упорядоченность в параллельных сценариях программирования.
Таким образом, понимание модели памяти Java очень важно, если вы хотите создавать высокопроизводительные параллельные программы.Модель памяти Java указывает, как и когда можно увидеть значения общих переменных, измененных другими потоками, и как при необходимости синхронизировать доступ к общим переменным..
3.1 Абстракция модели памяти Java
В Яве,Все поля экземпляра, статические поля и элементы массива хранятся в куче памяти, которая распределяется между потоками..Локальные переменные, формальные параметры метода и параметры обработчика исключенийНе разделены между потоками, они не имеют проблем с видимостью памяти и не зависят от модели памяти.
Связь между потоками Java регулируется моделью памяти Java (JMM), которая определяет, когда записи потока в общую переменную видны другому потоку..从抽象的角度来看,JMM定义了线程和主内存之间的抽象关系:
Переменные общей памяти между потоками в основной памяти (основная память), каждый поток имеет частную локальную память (локальную память), локальная память хранит копию потока для чтения/записи общих переменных.Локальная память является абстракцией JMM и на самом деле не существует. Он охватывает кеши, буферы записи, регистры и другие оптимизации оборудования и компилятора..
Из приведенного выше рисунка видно, что если поток A и поток B хотят взаимодействовать, они должны выполнить следующие два шага:
- Во-первых, поток A обновляет обновленную общую переменную из локальной памяти A в основную память;
- Затем поток B переходит в основную память, чтобы прочитать общую переменную, которую ранее обновил поток A;
На следующих диаграммах показаны эти два шага:
Как показано на рисунке выше, в локальной памяти A и B есть копии общей переменной x в основной памяти. Предположим, что изначально все значения x в этих трех памяти равны 0. Когда поток A выполняется, он временно сохраняет обновленное значение x (при условии, что значение равно 1) в своей собственной локальной памяти A.Когда потоку A и потоку B необходимо взаимодействовать, поток A сначала обновляет измененное значение x из своей локальной памяти в основную память, и в это время значение x в основной памяти становится равным 1. Затем поток B переходит в основную память для чтения обновленного значения x потока A. В это время значение x локальной памяти потока B также становится равным 1..
В целом, эти два шага представляют собой поток A, отправляющий сообщение потоку B, и этот коммуникационный процесс должен проходить через основную память.JMM предоставляет Java-программистам гарантии видимости памяти, контролируя взаимодействие между основной памятью и локальной памятью каждого потока..
3.2 Изменение порядка
Для повышения производительности при выполнении программы,Компиляторы и процессоры часто меняют порядок инструкций. Существует три типа переупорядочивания:
- Переупорядочивание, оптимизированное для компилятора. Компилятор может изменить порядок выполнения операторов без изменения семантики однопоточной программы.
- Параллельное переупорядочивание на уровне инструкций. Современные процессоры используют параллелизм на уровне инструкций (ILP) для перекрытия выполнения нескольких инструкций.При отсутствии зависимостей по данным процессор может изменить порядок выполнения соответствующих машинных инструкций для оператора.
- Переупорядочивание системы памяти. Поскольку процессор использует кэши и буферы чтения/записи, это делает возможным выполнение операций загрузки и сохранения не по порядку.
От исходного кода Java до окончательного фактического выполнения последовательности инструкций она претерпит следующие три переупорядочения:
Приведенное выше 1 принадлежит компилятору порядок заусенцев, 2 и 3 принадлежат процессору переупорядочения.这些重排序都可能会导致多线程程序出现内存可见性问题。
для компилятора, правила переупорядочения компилятора JMM запрещают определенные типы переупорядочения компилятора (не все переупорядочения компилятора должны быть запрещены).
Для изменения порядка процессоров, правила переупорядочивания процессоров JMM потребуют от компилятора Java вставлять инструкции определенных типов барьеров памяти (барьеры памяти, интеллектуальное ограничение памяти) при создании последовательности инструкций,Отключение определенных типов переупорядочения процессоров с помощью инструкций барьера памяти (не все переупорядочения процессоров запрещены).
JMM принадлежит модели памяти уровня языка,Это гарантирует, что из разных компиляторов и разных процессорных платформ перераспределяются определенные типы переупорядочения компилятора и процессоров., который предоставляет программистам стабильные гарантии видимости памяти.
3.3 Изменение порядка процессоров
современные процессоры используютбуфер записиПриходит для временного сохранения данных, записанных в память.Конвейер инструкций буфера записи может обеспечить непрерывную работу, можно избежать ожидания процессором остановки для создания задержки записи данных в память.. В то же время, путем обновления буфера записи пакетной способ, и написание нескольких пишетов в том же адресе памяти в вычислительном буфере записи,Может уменьшить занятость шины памяти. Несмотря на множество преимуществ записи буферов,Но буфер записи на каждом процессоре виден только процессору, на котором он находится.. Эта функция существенно влияет на порядок выполнения операций с памятью:
Порядок выполнения процессором операций чтения/записи в память не обязательно совпадает с порядком реальных операций чтения/записи в памяти!
Если предположить, что процессор A и процессор B выполняют доступ к памяти параллельно в программном порядке, они могут получить x = y = 0. Конкретные причины показаны на рисунке ниже:
Процессоры A и B одновременно записывают общую переменную в буфер записи (A1, B1), затем читают другую общую переменную (A2, B2) из памяти и, наконец, записывают грязные данные, хранящиеся в буфере записи. (А3, В3).При выполнении с этим временем программа может получить x = y = 0.
Судя по порядку, в котором фактически происходят операции с памятью, операция записи A1 фактически не выполняется до тех пор, пока процессор A не выполнит A3 для обновления своего буфера записи. Хотя порядок, в котором процессор А выполняет операции с памятью, таков: A1 -> A2, порядок, в котором фактически выполняются операции с памятью, таков: A2 -> A1.В этот момент порядок операций с памятью процессора А изменяется..
Ключ вот в том, что из-за буфера записи видно только к собственным процессоре, он приведет к последовательному процессору для выполнения операций памяти может быть несовместимым с фактической реализацией порядка операций памяти.Современные процессоры позволяют переупорядочивать операции записи-чтения памяти, поскольку они используют буферы записи..
3.4 Инструкции барьера памяти
Ниже приведен список типов переупорядочения, разрешенных распространенными процессорами:
«N» в приведенной выше ячейке таблицы означает, что процессор не позволяет переупорядочивать две операции, а «Y» означает, что переупорядочивание разрешено. Из вышеприведенной таблицы мы видим, что:Общий процессор нагрузки на хранилище позволяет переупорядочить; общие процессорные операции разрешено полагаться на наличие данных.. sparc-TSO и x86 имеют относительно сильные модели процессорной памяти, они позволяют только переупорядочивать операции записи-чтения (поскольку они оба используют буферы записи).
Чтобы гарантировать видимость памяти,Компилятор Java вставляет инструкции барьера памяти в соответствующие точки сгенерированной последовательности инструкций, чтобы запретить определенные типы переупорядочения процессора.. JMM делит инструкции барьера памяти на следующие четыре категории:
3.5 happens-before
Использование модели памяти JSR-133happens-beforeКонцепция видимости памяти между операциями.В JMM операция выполняется, если результат необходимости в другой видимой операции должен существовать до того, как произойдет связь между двумя операциями.. Две упомянутые здесь операции могут выполняться либо внутри потока, либо между разными потоками.
Правила «происходит до», тесно связанные с программистами, следующие:
правила порядка программы: Каждая операция в потоке выполняется до любых последующих операций в этом потоке.
Правила блокировки монитора: Разблокировать блокировку монитора, бывает - до этого блокировать блокировку монитора.
правила изменяемой переменной: Напишите волатильный домен, происходит - прежде чем читать в этом летучей местности в любой следующем.
транзитивное правило: Если А происходит раньше В, а В происходит раньше С, то А происходит раньше С.
Обратите внимание, что между двумя операциями существует отношение «происходит до», что не означает, что предыдущая операция должна быть выполнена до последней операции!происходит-прежде только требует, чтобы предыдущая операция (результат выполнения) была видна следующей операции, а предыдущая операция упорядочена перед второй операцией (первая видна и упорядочена перед второй операцией).
Как показано на фиг.Правило «происходит до» обычно соответствует нескольким правилам переупорядочения компилятора и процессора.. Для Java-программистов правило «происходит до» простое и легкое для понимания, что избавляет их от необходимости изучать сложные правила переупорядочивания и конкретную реализацию этих правил, чтобы понять гарантию видимости памяти, предоставляемую JMM.
3.6 Зависимости данных
Если две операции обращаются к одной и той же переменной, и одна из двух операций является операцией записи, то между двумя операциями существует зависимость данных.. Существует три типа зависимостей данных:
В приведенных выше трех случаях, если порядок выполнения двух операций изменен, результат выполнения программы будет изменен.
Как упоминалось ранее, компилятор и процессор могут быть отсортированы по операции.При перестановке компилятора и процессора зависимые от данных, компилятор и процессор не меняют порядок выполнения двух операций зависимостей данных..
Примечание, здесьЗависимость данных существует только для операций, выполняемых в одном процессоре и одном потоке, а зависимость данных между разными процессорами и между разными потоками не учитывается компилятором и процессором..
3.7 семантика «как если бы»
Смысл семантики «как-будто-сериал» означает:Независимо от того, насколько переупорядочены (компилятор и процессор для увеличения параллелизма), результат выполнения (однопоточной) программы не может быть изменен. Компилятор, среда выполнения и процессор должны подчиняться семантике как-если-последовательной.
В целях соответствия компиляторам и процессорам, как если бы они были последовательными, не переупорядочивайте операции, которые имеют зависимости от данных, поскольку такое переупорядочение изменит результат выполнения.. Но если между операциями нет зависимостей по данным, эти операции могут быть переупорядочены компилятором и процессором.
Например:
double pi = 3.14; // A
double r = 1.0; // B
double area = pi * r * r; // C
Зависимости данных трех вышеуказанных операций показаны на следующем рисунке:
Как показано на рисунке выше, существует зависимость данных между A и C, а также зависимость данных между B и C.Следовательно, C нельзя переупорядочить перед A и B в окончательной выполненной последовательности инструкций (C помещается перед A и B, и результат программы будет изменен). Но между A и B нет зависимости данных, компилятор и процессор могут изменить порядок выполнения между A и B.. На следующих диаграммах показаны две возможные последовательности выполнения этой программы:
В вычислительной технике программные технологии и аппаратные технологии имеют общую цель:Максимально развивать степень параллелизма без изменения результата выполнения программы. Компиляторы и процессоры соответствуют этой цели, начиная сhappens-beforeМы видим, что JMM также соответствует этой цели.
4 Реализация модели памяти Java
Друзья, знакомые с многопоточностью Java, знают, что в Java предусмотрен ряд ключевых слов, связанных с параллельной обработкой, например:volatile
,synchronized
,final
,concurrent
пакет и т. д. На самом деле этоМодель памяти Java инкапсулирует некоторые ключевые слова, предоставляемые программистам после базовой реализации..
При разработке многопоточного кода мы можем напрямую использоватьsynchronized
В ожидании ключевых слов для управления параллелизмом вам не нужно заботиться об оптимизации базового компилятора, согласованности кэша и других проблемах. так,Модель памяти Java, в дополнение к определению набора спецификаций, также предоставляет ряд примитивов, которые инкапсулируют базовую реализацию для непосредственного использования разработчиками..
4.1 Атомарность
В Java для обеспечения атомарности предусмотрены две высокоуровневые инструкции байт-кода.monitorenter
иmonitorexit
, эти два байт-кода, соответствующие ключевые слова в Javasynchronized
.
Итак, в Java вы можете использоватьsynchronized
чтобы гарантировать атомарность операций внутри методов и блоков кода.
4.2 Видимость
Модель памяти Java реализуется путем синхронизации нового значения обратно в основную память после изменения переменной и обновления значения переменной из основной памяти до того, как переменная будет прочитана, что зависит от основной памяти в качестве среды передачи..
на Явеvolatile
关键字提供了一个功能,那就是被其修饰的变量在被修改后可以立即同步到主内存,被其修饰的变量在每次是用之前都从主内存刷新。 следовательно,можно использоватьvolatile
Для обеспечения видимости переменных во время многопоточных операций.
Кромеvolatile
, на Явеsynchronized
иfinal
Два ключевых слова также могут обеспечить видимость. Просто реализация отличается, поэтому я не буду ее здесь распространять.
4.3 упорядоченность
В Java вы можете использоватьsynchronized
иvolatile
Для обеспечения упорядоченности операций между несколькими потоками. Реализация отличается:
Ключевое слово volatile отключит перестановку команд;
Синхронизированное ключевое слово гарантирует, что одновременно разрешена только одна операция потока;