Интервьюер не ожидал Летучего, я мог говорить с ним полчаса

интервью Java

Ставьте лайк и смотрите снова, формируйте привычку, ищите в WeChat【Третий принц Ао Бин] Обратите внимание на этот инструмент человека, который борется за выживание в Интернете.

эта статьяGitHub github.com/JavaFamilyВключено, и есть полные тестовые площадки, материалы и мой цикл статей для интервью с производителями первой линии.

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

Давайте последуем за Bing Bing, чтобы увидеть демо-код

Вы обнаружите, что он никогда не будет выводитьсячто-тоВ этом фрагменте кода разумно сказать, что поток изменил переменную флага, поэтому основной поток также может получить к ней доступ?

Почему это происходит? Тогда нам нужно поговорить о чем-то другом.

JMM (JavaMemoryModel)

JMM: Модель памяти Java — это модель памяти, определенная в спецификации виртуальной машины Java. Модель памяти Java стандартизирована и скрывает разницу между различными базовыми компьютерами (注意这个跟JVM完全不是一个东西,只有还有小伙伴搞错的).

Перед официальным чатом поговорим о модели памяти современных компьютеров.

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

На самом деле скорость процессора и памяти в ранних компьютерах одинакова, но в современных компьютерахcpu的指令速度远超内存的存取速度, Поскольку вычислительная скорость запоминающего устройства компьютера и процессора различается на несколько порядков, современные компьютерные системы вынуждены добавлять слой, скорость чтения и записи которого максимально приближена к вычислительной скорости процессора.高速缓存(Cache)как буфер между памятью и процессором.

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

Взаимодействие с хранилищем на основе кеша хорошо решает противоречие между скоростью процессора и памятью, но также усложняет компьютерную систему, поскольку создает новую проблему:缓存一致性(CacheCoherence).

В многопроцессорной системе каждый процессор имеет свой собственный кэш, и они разделяют одну и ту же основную память (MainMemory).

Тогда мы можем поговорить о JMM.

JMM

Java内存模型(JavaMemoryModel)Описывает правила доступа к различным переменным (общие переменные потока) в программах Java, а также низкоуровневые сведения о хранении, сохранении и чтении переменных из памяти в JVM.

JMM имеет следующие положения:

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

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

线程对变量的所有的操作(读,取)都必须在工作内存中完成,而不能直接读写主内存中的变量.

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

Связь между локальной памятью и основной памятью:

Именно из-за этого механизма существует проблема видимости, поэтому мы обсудим решение видимости.

Решения для обеспечения видимости

замок

Почему блокировка решает проблему видимости?

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

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

Volatile украшает общие переменные

Код в начале должен выглядеть так после оптимизации:

Что сделал Летучий?

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

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

Кажется, легко добавить ключевое слово, но на самом деле он много работал за кулисами и молча заплатил много.Позвольте мне объяснить значение этих терминов из протокола когерентности кеша на уровне компьютера.

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

Если это произойдет, чьи кэшированные данные используются при синхронизации с основной памятью?

Чтобы решить проблему согласованности, каждый процессор должен следовать некоторым протоколам при доступе к кешу и работать в соответствии с протоколом при чтении и записи, к таким протоколам относятся MSI,MESI(IllinoisProtocol), MOSI, Synapse, Firefly и DragonProtocol и т. д.

Поговорим о МЭСИ от Intel.

MESI (протокол когерентности кэша)

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

Что касается того, как узнать, недействительны ли данные?

нюхать

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

Я не знаю, обнаружили ли вы недостатки обнюхивания?

автобусная буря

Из-за протокола согласованности кэша MESI Volatile, который требует постоянного прослушивания основной памяти и непрерывного зацикливания cas, недопустимые взаимодействия могут привести к пиковой пропускной способности шины.

Так что не используйте часто Volatile Что касается того, когда использовать Volatile и когда использовать блокировки, это зависит от сцены.

Давай поговорим снова指令重排序Проблема

Отключить переупорядочивание инструкций

Что такое переупорядочить?

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

Какие бывают виды переоформления? Каковы переупорядочения от исходного кода до окончательного исполнения?

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

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

Поэтому компиляторы и процессоры часто меняют порядок инструкций при выполнении программ для повышения производительности.

Как правило, переупорядочивание можно разделить на следующие три типа:

  • Оптимизированное компилятором переупорядочивание. Компилятор может изменить порядок выполнения операторов без изменения семантики однопоточной программы;

  • Параллельное переупорядочивание на уровне инструкций. Современные процессоры используют параллелизм на уровне инструкций для перекрытия выполнения нескольких инструкций. Если нет зависимости данных, процессор может изменить порядок выполнения соответствующих машинных инструкций оператора;

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

Здесь следует упомянуть еще об одном понятии.as-if-serial.

as-if-serial

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

Компилятор, среда выполнения и процессор должны подчиняться семантике как-если-последовательной.

Как Volatile гарантирует, что он не будет переупорядочен?

барьер памяти

Компилятор Java вставит соответствующую позицию при создании серии инструкций.内存屏障инструкции по отключению определенных типов переупорядочения процессоров.

Чтобы достичь семантики памяти volatile, JMM ограничит определенные типы переупорядочения компилятора и процессора, а JMM сформулирует таблицу правил переупорядочения volatile для компилятора:

Следует отметить, что: записи volatile предшествуют и следуютВставьте барьеры памяти отдельно, в то время как энергозависимая операция чтенияВставьте два барьера памяти позади.

Писать

читать

Я упомянул принцип переупорядочивания выше.Чтобы повысить скорость обработки, JVM будет компилировать и оптимизировать код, то есть оптимизация переупорядочивания инструкций.Переупорядочивание инструкций при параллельном программировании принесет некоторые риски безопасности: такие как множественная невидимость между операциями потока.

Если программистов попросят понять эти базовые реализации и конкретные правила, нагрузка на программистов будет слишком велика, что серьезно повлияет на эффективность параллельного программирования.

Начиная с JDK5, предлагаетсяhappens-beforeКонцепция видимости памяти между операциями через эту концепцию.

happens-before

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

volatile域规则:对一个volatile域的写操作,happens-before于任意线程后续对这个volatile域的读。

Если теперь мой falg стал ложным, то последняя операция должна знать, что я изменился.

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

Атомарность не гарантируется

Это операция, которая либо полностью завершается успешно, либо полностью терпит неудачу.

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

Решение также простое: либо используйте атомарные классы, такие как AtomicInteger, либо блокируйте (记得关注Atomic的底层).

применение

Есть 8 способов написать синглтон, позвольте мне рассказать об особом, который включает в себя Volatile.

Вы можете удивиться, зачем проверять дважды? Что, если я не использую Volatile?

Я расскажу об этом первым禁止指令重排序преимущества.

Объекты фактически создают объекты с помощью следующих шагов:

  • Выделить место в памяти.
  • Вызовите конструктор для инициализации экземпляра.
  • обратный адрес для ссылки

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

Но другие темы, чтобы судить о экземпляре! =null, используйте его напрямую, по сути, этот объект является полуфабрикатом, тогда возникает исключение нулевого указателя.

Как обеспечивается видимость?

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

Я упомянул volatile и synchronized выше, поэтому позвольте мне рассказать об их различиях.

Разница между volatile и синхронизированным

Volatile может изменять только переменные экземпляра и переменные класса, а synchronized может изменять методы и блоки кода.

Volatile гарантирует видимость данных, но не гарантирует атомарность (многопоточные операции записи не гарантируют потокобезопасности), а synchronized — это эксклюзивный (взаимное исключение) механизм. Volatile используется для запрета переупорядочивания инструкций: он может решить проблему неупорядоченного выполнения кода инициализации одноэлементного дважды проверенного объекта.

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

Суммировать

  1. Модификатор volatile подходит для следующих сценариев: свойство совместно используется несколькими потоками, один из которых изменяет свойство, а другие потоки могут немедленно получить измененное значение, например booleanflag, или в качестве триггера для облегченной синхронизации.
  2. Операции чтения и записи изменчивых свойств не блокируются и не могут заменить синхронизированные, поскольку не обеспечивают атомарность и взаимное исключение. Поскольку он не требует блокировки, ему не нужно тратить время на получение и снятие блокировок, поэтому он недорогой.
  3. Volatile может воздействовать только на свойства.Мы используем volatile для изменения свойств, чтобы компиляторы не изменяли порядок инструкций для этого свойства.
  4. Volatile обеспечивает видимость, любое его изменение любым потоком будет немедленно видно другим потокам, volatile атрибуты не будут кэшироваться потоками, всегда из основного читать по памяти.
  5. Volatile предоставляет гарантию «происходит до того, как запись в изменчивую переменную v произойдет до того, как все последующие чтения v другими потоками».
  6. volatile может сделать длинные и двойные присваивания атомарными.
  7. volatile может обеспечить видимость и запретить переупорядочивание команд при одноэлементной двойной проверке, тем самым гарантируя безопасность.

Примечание: Если вы сможете освоить весь вышеперечисленный контент, думаю, Volatile будет отличным бонусом для интервьюера, а вот про нижний слой памяти компьютера я много не рассказывал, тогда всем нужно идти наверстывать уроки позже , если вы подождете И, можете также подождать, пока я не напишу главу об основах компьютера.

болтовня

img
img

Из-за обновления статей и видео Бинбин уже больше полугода не отдыхает по выходным, спешит на рабочем месте компании, пытается найти время, чтобы выйти поиграть, думая, что один день ежегодного отпуска — это бесполезно, он пригласил его пойти поиграть на два дня.

Таким образом, я смогу вернуться пораньше 1 мая и подготовиться к возобновлению обновления видео. Пока вы смотрите, Ао Бин должен быть в поезде для поездки. Да, я понесу эту сумку. Когда я закончу писать, я я еще не уверен Куда вы идете, я желаю вам всем счастливого праздника заранее.

Я Ао Бин, мастер по инструментам, который живет в Интернете.

Чем больше вы знаете, тем больше вы не знаете,талантнаш【Три подряд】Это самая большая движущая сила для создания Bing Bing, увидимся в следующем выпуске!

Примечание. Если в этом блоге есть какие-либо ошибки и предложения, оставьте сообщение,высказываться!


Статья постоянно обновляется, вы можете искать в WeChat "Третий принц Ао Бин"Прочтите это в первый раз, ответьте [материал】【интервью】【резюме] Подготовленные мной материалы интервью и шаблоны резюме крупных заводов первой линии, эта статьяGitHub github.com/JavaFamilyОн был включен, и есть полные тестовые сайты для интервью с крупными заводами.Добро пожаловать в Star.