anchor.diff:  * L3 - кэш на процессоре, общий для всех ядер. Скорость доступа порядка 20 нс.
   Может быть достаточно большим (8-32 MB). 
   
  -Появление кэшей вызывало тот факт, что скорость работы процессора начала
  -становится намного больше скорости доступа к памяти. Поэтому для того, чтобы 
  -избежать огромных задержек по доступу к данным из основной памяти (порядка 60 нс),
  -производителями процессоров были добавлены кэши на процессорах для быстрого
  -выполнения операций над "горячими" данными. 
  +Появление кэшей вызывало тот факт, что скорость работы процессора начала становится намного больше скорости доступа к памяти. Поэтому для того, чтобы избежать огромных задержек по доступу к данным из основной памяти (порядка 60 нс), производителями процессоров были добавлены кэши на процессорах для быстрого выполнения операций над "горячими" данными. 
   
   === *Что такое Memory wall?*
   
  -_Memory wall_ - это термин, описавающий ограничение производительности
  -вычислительных систем скоростью доступа к памяти. Несмотря на то, что частота
  -процессоров в 70-90-е годы увеличивалась в 2 раза каждые 2 года, скорость
  -доступа к памяти не увеличивалсь с такой же степенью. 
  -
  -В итоге производительность системы в целом упиралась в производительности 
  -памяти, так как процессоры не могли работать на своей полной вычислительной
  -мощности.
  +_Memory wall_ - это термин, описавающий ограничение производительности вычислительных систем скоростью доступа к памяти. Несмотря на то, что частота процессоров в 70-90-е годы увеличивалась в 2 раза каждые 2 года, скорость доступа к памяти не увеличивалсь с такой же степенью. В итоге производительность системы в целом упиралась в производительности памяти, так как процессоры не могли работать на своей полной вычислительной мощности.
   
   === *Что такое Memory Hierarchy?*
   
  -_Memory Hierarchy_ - термин для описания производительности систем хранения
  -данных. Чем ниже уровень иерархии, тем дешевле цена системы хранения и больше
  -время доступа к ней. Обычно выделяют 4 уровня:
  +_Memory Hierarchy_ - термин для описания производительности систем хранения данных. Чем ниже уровень иерархии, тем дешевле цена системы хранения и больше время доступа к ней. Обычно выделяют 4 уровня:
   
   * Регистры и кэши процессора (скорость доступа порядка 100-500 Гб/c)
   * Оперативная память (скорость доступа порядка 1-10 Гб/c)
   * Диски (скорость доступа порядка 100-500 Мб/c)
  -* Третичные память (скорость доступа порядка 10-100 Мб/c)
  +* Третичные хранилища (скорость доступа порядка 10-100 Мб/c)
   
   === *Что такое Cache line? В виде каких эффектов проявляется?*
   
  -_Cache line_ - блок данных(обычно 64 байт), в котором передаются данные между
  -процессором и оперативной памятью. Когда процессору нужно прочитать данные
  -по конкретному адресу из опертивной памяти, он вместо 1 байта читает сразу
  -блок данных и кладет этот блок в кэш. 
  -
  -Такая оптимизация хорошо работает в случае, если данные, над которыми
  -работает процессор, обладают хорошей локальностью. Тогда при следующем
  -чтении данные уже будут в кэше и процессору не нужно будет делать дорогой
  -запрос в оперативную память.
  +_Cache line_ - блок данных(обычно 64 байт), в котором передаются данные между процессором и оперативной памятью. Когда процессору нужно прочитать данные по конкретному адресу из опертивной памяти, он вместо 1 байта читает сразу блок данных и кладет этот блок в кэш. Такая оптимизация хорошо работает в случае, если данные, над которыми работает процессор, обладают хорошей локальностью. Тогда при следующем
  +чтении данные уже будут в кэше и процессору не нужно будет делать дорогой запрос в оперативную память.
   
   === *Что такое False sharing? Плохо это или хорошо? Как с этим бороться?*
   
  -_False sharing_ - эффект при котором данные, не связанные с друг другом, попадают
  -в одну кэш-линию. В итоге когда изменяется одна из частей данных в кэш-линии,
  -вся линия инвалидируется. Это плохой эффект, так как он может вызывать трешинг
  -(thrashing) - постоянную подгрузку и инвалидацую данных их кэша. Например, часто
  -читаемые данные могут попать на одну линию с часто записываемыми. При каждой 
  -записи линия будет инвалидироваться из кэша вместе с часто читаемыми данными, 
  -хотя сами данные не менялись.
  -
  -Бороться можно с помощью техники паддинга (padding). Часто читаемые данные
  -выравниваются по модулю длины кэш-линии с помощью фиктивных байтов. В итоге
  -исключается вариант, когда вместе с ними на кэш-линию попадают "случайные"
  -данные.
  +_False sharing_ - эффект при котором данные, не связанные с друг другом, попадают в одну кэш-линию. В итоге когда изменяется одна из частей данных в кэш-линии, вся линия инвалидируется. Это плохой эффект, так как он может вызывать трешинг (thrashing) - постоянную подгрузку и инвалидацую данных их кэша. Например, часто читаемые данные могут попать на одну линию с часто записываемыми. При каждой записи линия будет инвалидироваться из кэша вместе с часто читаемыми данными, хотя сами данные не менялись.
  +
  +Бороться можно с помощью техники паддинга (padding). Часто читаемые данные выравниваются по модулю длины кэш-линии с помощью фиктивных байтов. В итоге исключается вариант, когда вместе с ними на кэш-линию попадают "случайные" данные.
   
   === *Что такое Memory padding?*
   
  -_Memory padding_ - это техника выравнивая структуры данных по границам читаемого
  -процессором размера слова. Она позволяет быть уверенным, что данные всегда
  -попадут на одну кэш-линию и займут ее экслюзивно. Это позволяет избежать
  -трешинга кэша, в случае, если на линию попадают не соотносящиеся друг с другом 
  -данные.
  +_Memory padding_ - это техника выравнивая структуры данных по границам читаемого процессором размера слова. Она позволяет быть уверенным, что данные всегда попадут на одну кэш-линию и займут ее экслюзивно. Это позволяет избежать трешинга кэша, в случае, если на линию попадают не соотносящиеся друг с другом данные.
   
   === *Что такое Cache pollution? Плохо это или хорошо? Как с этим бороться?*
   
  -_Cache pollution_ - эффект при котором, происходит трешинг кэшей из-за того, что
  -активные данные не имеют локальности. Если данные на находятся на одной кэш-линии,
  -то при чередующем обращении к 1-му и 2-му набору данных, кэш будет постоянно
  -инвалидировать и подгружать данные.
  -
  -Это плохой эффект, так как он может привести к заметному падению производительности
  -приложения без видимой для программиста причины. 
  -
  -Бороться можно изменением подхода к обработке данных. Идея заключается в том,
  -чтобы в один период времени работать только с "горячими" данными в кэше и
  -начинать работу со следующим набором данных только после того, как первый
  -больше не нужен.
  +_Cache pollution_ - эффект при котором, происходит трешинг кэшей из-за того, что активные данные не имеют локальности. Если данные на находятся на одной кэш-линии, то при чередующем обращении к 1-му и 2-му набору данных, кэш будет постоянно инвалидировать и подгружать данные.
  +Это плохой эффект, так как он может привести к заметному падению производительности приложения без видимой для программиста причины. 
  +Бороться можно изменением подхода к обработке данных. Идея заключается в том, чтобы в один период времени работать только с "горячими" данными в кэше и начинать работу со следующим набором данных только после того, как первый больше не нужен.
   
   === *Что такое Cache miss? Плохо это или хорошо? Как с этим бороться?*
   
  -_Cache miss_ - ситуация, когда запрашиваемого блока данных нет в кэше. В общем
  -случае, это не является плохим эффектом, так если данные запрашиваются первый
  -раз, то они все равно должны быть загружены в кэш. Процессоры часто спекулируют
  -о паттернах доступа данных и вместе с запрашиваемым блоком данных кэшируют
  -больший блок данных, полагаясь на локальность данных. Поэтому для близко лежащих
  -данных промахов не будет. Проблема возникает, когда промахов становится очень
  -много. Это значит, что данные не локальны и кэш не может эффективно предпогружать
  -данные.
  -
  -Бороться с промахами можно с помощью изменения расположения данных в памяти
  -(большая локальность), изменением патернов доступа к данным (избегать трешинга),
  -тюнингом размера кэша.
  +_Cache miss_ - ситуация, когда запрашиваемого блока данных нет в кэше. В общем случае, это не является плохим эффектом, так если данные запрашиваются первый раз, то они все равно должны быть загружены в кэш. Процессоры часто спекулируют о паттернах доступа данных и вместе с запрашиваемым блоком данных кэшируют больший блок данных, полагаясь на локальность данных. Поэтому для близко лежащих данных промахов не будет. Проблема возникает, когда промахов становится очень много. Это значит, что данные не локальны и кэш не может эффективно предпогружать
  +данные. Бороться с промахами можно с помощью изменения расположения данных в памяти (большая локальность), изменением патернов доступа к данным (избегать трешинга), тюнингом размера кэша.
   
   === *В чем разница между SMP и NUMA? Как это сказывается на программах?*
   
  -SMP-системы имеют одну большую память, которая распределяется между процессорами.
  -Процессоры общаются с памятью через глобальную шину данных. В NUMA-системах, в
  -свою очередь, для каждого процессора есть своя локальная память и локальная шина. 
  -Это сильно снижает трафик на шинах в случае если процессоры работают над
  -независимыми данными. 
  -
  -В операционной системе должна быть поддержка NUMA-систем (специальный аллокатор
  -памяти, привязка программ к процессору), иначе производительность системы будет
  -намного хуже, чем SMP из-за отсуствия локальности данных и, следовательно, большой
  -цены (~100 нс) последующей загрузки данных не из локальной памяти для процессора. 
  +SMP-системы имеют одну большую память, которая распределяется между процессорами. Процессоры общаются с памятью через глобальную шину данных. В NUMA-системах, в свою очередь, для каждого процессора есть своя локальная память и локальная шина. Это сильно снижает трафик на шинах в случае если процессоры работают над независимыми данными. В операционной системе должна быть поддержка NUMA-систем (специальный аллокатор памяти, привязка программ к процессору), иначе производительность системы будет намного хуже, чем SMP из-за отсуствия локальности данных и, следовательно, большой цены (~100 нс) последующей загрузки данных не из локальной памяти для процессора. 
   
   === *В чем разница между Multicore и Multisocket?*
   
   * Multicore - это один процессор с несколькими ядрами.
   * Multisocket - это несколько одноядерных процессоров.
   
  -Multisocket системы дороже, чем Multicore (нужен отдельный сокет на каждый
  -процессор. А каждый процессор в свою очередь является чипом). Они лучшеработают,
  -если процессоры сильно не зависимы от друг друга (обрабатывают разный набор
  -данных). Тогда можно избежать трешинга L3-кэшей, так как они у процессоров
  -раздельные. 
  -
  -В общем случае Multicore системы работают лучше, так как программы обычно не
  -настолько требовательны к ресурсам, чтобы потреблять всю вычислительную мощность
  - ядра/процессора. При этом засчет L3 кэша переключение программ с ядро на ядро
  -в multicore-процессорах происходит быстрее.
  +Multisocket системы дороже, чем Multicore (нужен отдельный сокет на каждый процессор. А каждый процессор в свою очередь является чипом). Они лучшеработают, если процессоры сильно не зависимы от друг друга (обрабатывают разный набор данных). Тогда можно избежать трешинга L3-кэшей, так как они у процессоров раздельные. В общем случае Multicore системы работают лучше, так как программы обычно не настолько требовательны к ресурсам, чтобы потреблять всю вычислительную мощность ядра/процессора. При этом засчет L3 кэша переключение программ с ядро на ядро в multicore-процессорах происходит быстрее.
   
   === *Что такое Thread affinity? Можно ли сделать в Java?*
   
  -_Thread affinity_ - это возможность привязать выполнение потока к определенному
  -ядру. Это является оптимизацией производительности в мультипроцессорных системах.
  - Ее цель - увеличить процент "попадания" в кэш при доступе к данным. Смысл 
  -оптимизации в извлечении пользы из наблюдения о том, что большинство потоков 
  -обычно работают с одним и тем же набором данных. То есть после того как поток
  -прервется планировщиком и заново получит квант времени, ему лучше выполнится на
  -том же ядре, так как скорее всего оно уже будет содержать нужные данные в своем
  -кэше.
  -
  -Из Java напрямую сделать нельзя, но есть возможность сделать через JNA/JNI, если 
  -известна целевая платформа.
  +_Thread affinity_ - это возможность привязать выполнение потока к определенному ядру. Это является оптимизацией производительности в мультипроцессорных системах. Ее цель - увеличить процент "попадания" в кэш при доступе к данным. Смысл оптимизации в извлечении пользы из наблюдения о том, что большинство потоков обычно работают с одним и тем же набором данных. То есть после того как поток прервется планировщиком и заново получит квант времени, ему лучше выполнится на том же ядре, так как скорее всего оно уже будет содержать нужные данные в своем кэше. Из Java напрямую сделать нельзя, но есть возможность сделать через JNA/JNI, если известна целевая платформа.
   
   === *Что такое Inter Thread Parallelism? Task Parallelism?*
   
  -Честно говоря, термины мне не известны. Возможно, имеется ввиду 
  -_hyper threading_?
  -
  -Это технология симуляции нескольких процессоров для операционной системы засчет
  -дублирования вычислительных регистров. Операционная система планирует 2 потока
  -на "виртуальные" процессоры, и кладет данные в регистры. Процессор же в свою
  -очередь выполняет инструкции последовательно. Идея в том, чтобы уменьшить цену
  -переключения потоков, передавая сразу 2 потока инструкций на процессор.
  -
  -Процессор, имея больше информации о потоке инструкций, может делать больше
  -спекулятивных оптимизаций.
  +Честно говоря, термины мне не известны. Возможно, имеется ввиду _hyper threading_?
  +
  +Это технология симуляции нескольких процессоров для операционной системы засчет дублирования вычислительных регистров. Операционная система планирует 2 потока на "виртуальные" процессоры, и кладет данные в регистры. Процессор же в свою очередь выполняет инструкции последовательно. Идея в том, чтобы уменьшить цену переключения потоков, передавая сразу 2 потока инструкций на процессор. Процессор, имея больше информации о потоке инструкций, может делать больше спекулятивных оптимизаций.
   
   === *Что такое Branch Prediction?*
   
  -_Branch Prediction_ - это предсказание процессором перехода на определенную ветку
  -выполнения кода. Так как современные процессоры работают конвеером и переходят
  -к следующей инструкции до ее выполнения, то очень неэффективно ждать, пока
  -определится результат условия.
  -
  -Поэтому процессоры спекулятивно выполняют одну из веток и только потом определяют,
  -была догадка правильной или нет. В случае, если процессор не угадывает ветку
  -выполнения, то он возвращается назад и начинает конвеер сначала.
  +_Branch Prediction_ - это предсказание процессором перехода на определенную ветку выполнения кода. Так как современные процессоры работают конвеером и переходят к следующей инструкции до ее выполнения, то очень неэффективно ждать, пока определится результат условия. Поэтому процессоры спекулятивно выполняют одну из веток и только потом определяют, была догадка правильной или нет. В случае, если процессор не угадывает ветку выполнения, то он возвращается назад и начинает конвеер сначала.
   
   === *Что такое Speculative Execution?*
   
  -_Speculative Execution_ - это оптимизация, при которой выполняется некоторая
  -часть кода до проверки необходимости ее выполнения. Идея заключается в
  -наблюдении о том, что многие условия на практике перенаправляют выполнению на
  -одну ветку, и очень редко на другую.
  -
  -Пример - проверка кода ошибки. В большинстве случаев операция завершится
  -успешно. Если процессор не делал бы спекулятивное выполнение, то он бы
  -вынужден был всегда ждать выполнения последней команды перед условием. А так
  -он может сразу переходить к ветке с успешным выполнением, не дожидаясь конца
  -выполнения операции. В редком случае ошибки процессор просто вернется к условию
  -и выполнит ветку обработки ошибки.
  +_Speculative Execution_ - это оптимизация, при которой выполняется некоторая часть кода до проверки необходимости ее выполнения. Идея заключается в наблюдении о том, что многие условия на практике перенаправляют выполнению на одну ветку, и очень редко на другую. Пример - проверка кода ошибки. В большинстве случаев операция завершится успешно. Если процессор не делал бы спекулятивное выполнение, то он бы вынужден был всегда ждать выполнения последней команды перед условием. А так он может сразу переходить к ветке с успешным выполнением, не дожидаясь конца выполнения операции. В редком случае ошибки процессор просто вернется к условию и выполнит ветку обработки ошибки.
   
   === *Сравните с точки зрения программиста — машину с четырехядерным процессором и двумя двухядерными процессорами*
   
  -В общем, для программиста нет никакой разницы. ОС в обоих случаях будет
  -показывать 4 доступных процессора.
  -
  -Единственный случай - это если имеется 2 большие независимые программы.
  -Тогда имеет смысл запустить их на разных физических процессорах, чтобы
  -избежать трешинга L1-L2 кэша.
  +В общем, для программиста нет никакой разницы. ОС в обоих случаях будет показывать 4 доступных процессора. Единственный случай - это если имеется 2 большие независимые программы. Тогда имеет смысл запустить их на разных физических процессорах, чтобы избежать трешинга L1-L2 кэша.
   
   === *Напишите программу, которая демонстрирует False sharing*
   
   См. https://github.com/arteam/100-Java-Concurrency-questions/tree/master/false-sharing[false-sharing]
   
  -Бенчмарк измеряет одновременное чтение и запись полей объекта в памяти.
  -По предположению в отстуствие паддинга должен проявляться эффект false sharing.
  -То есть записи в поле y должны делать кэш-линию инвалидной и вследствии чего
  -поле x будет читаться из памяти, а не из кэша.
  +Бенчмарк измеряет одновременное чтение и запись полей объекта в памяти. По предположению в отстуствие паддинга должен проявляться эффект false sharing. То есть записи в поле y должны делать кэш-линию инвалидной и вследствии чего поле x будет читаться из памяти, а не из кэша.
    
  -Из результатов бенчмарка видно, что в случае расположения полей объекта на одной
  -кэш-линии пропускная способность чтений в 3 раза хуже, чем в случае, когда JVM
  -выравнивает поле x по линии кэша.
  +Из результатов бенчмарка видно, что в случае расположения полей объекта на одной кэш-линии пропускная способность чтений в 3 раза хуже, чем в случае, когда JVM выравнивает поле x по линии кэша.
   
   ----
   c.g.a.b.FalseSharingBenchmark.contended:read      thrpt   10   60.870 ±  5.394  ops/us
  
positive.code: 
  === *Говорят, что Future/CompletableFuture — это монада. Что скажете?*
  
  Если упростить до невозможности, то монада - это структура, позволяющая
  представить значение в контексте выполнения операции. 
  
  То есть вместо того, чтобы работать с реальным значением, мы можем 
  представить его контейнером и дальше оперировать контейнером как 
  заместителем реального значения. У контейнера есть операции создания и 
  преобразования в контейнер с другим содержимым. Это позволяет программисту
  в некоторых местах сильно упростить код, когда его не интересуют 
  промежуточное состояние. Он может работать с монадой как с реальным 
  значением, не имея его представления.
  
  `Future` не является классической монадой, так как не позволяет
  преобразовывать себя в другие обещания выполнения. Можно только 
  параметризировать `Future` типом и создать его (например, через 
  `FutureTask`). 
  
  В свою очередь `CompletableFuture` позволяет преобразовывать одни 
  обещания выполнения в другие.
  
negative.code: 
  === *Что такое частичный порядок?*
  
  Частичный порядок - это математическое концепция, которая описывает отношение, которое обладает свойствами рефлексивности, антисимметричности и транзитивности. 
  
  * Рефлексивность означает, что отношение, примененное к одинаковым аргументам, является истинным.
  * Антисимметричность означает, что отношение не симметрично. То есть отношение, примененное к неодинаковым аргументам, поменняными местами, будет ложным.
  * Транзитивность означает, что если отношение истинно для аргументов *A* и *B* и для аргументов *A* и *C*, то оно истинно для аргументов *A* и *C*.
  
  Примером отношения частичного порядка является отношение *"быть делителем"*.
  
  === *Что такое отношение happens-before?*
  
  Отношение *happens-before*(происходит-до) является отношением частичного порядка между двумя операциями. Если одна операция *происходит до* другой, то ее результат видим и упорядочен для другой.
  
  === *Почему happens-before — это частичный порядок?*
  
  Потому что оно удовлетворяет определению частичного порядка.
  
  * Рефлексивность. Результат самой операции, очевидно, видим и упорядочен для  нее самой.
  
  * Антисимметричность. Если результат операции *A* видим и упорядочен для операции *B*, то результат операции *B* бы не видим и не упорядочен для *A*.
  
  Если бы *B* была бы видна для *A*, это значит, что для ее (*A*) локального времени *B* произошла до *A*. Так как результат *A* виден для *B*, то это значит, что для ее (*B*) локального времени *A* произошла до *B*. Так как отношение "произошел до/был раньше" транзитивно, из этого следует что *B* произшла до *B*. Получаем противоречие. Следовательно, *B* не может быть видна для *A*.
  
  * Транзитивность. Если результат операции *A* видим и упорядочен для *B* и результат *B* видим и упорядочен для *C*, то результат *A* видим и упорядочен для *С*.
  
  Так как *A* видна для *B*, то она произошла до *B* в ее локальном времени. Так как *B* видима для *C*, то она произошла до *C* в ее локальном времени. Так как отношение "произошел до/был раньше" транзитивно, то и операция *A* видима для *C*.
  
  === *Что такое data-race?*
  
  Data-race — это ситуация, когда несколько потоков одновременно/конкуретно работают с одной ячейкой памяти, и хотя бы один из них в нее пишет. В этом случае происходит "гонка". Результат чтения недетерминирован, так как зависит от того, какой из потоков выиграет "гонку" на физическом уровне.
  
  === *Какие гарантии на работу с volatile?*
  
  Запись в volatile поле *happens-before* чтения из volatile поля. 
  
  Соответственно, поток читающий из volatile поля гарантировано увидит корректное значение записи в это поля (а также всех предыдущих записей в потоке,изменившем это поле). Компилятору также запрещену переупорядочивать инструкции, которые работают с volatile полями с другими инструкциями. 
  
  То есть JMM *гарантирует*, что записи в потоке A, которые произошли до записи в volatile-поле, произошли и видимы для потока B, который читает это поле. 
  
  === *Какие гарантии на работу с final?*
  
  Запись в *final* поле (примитив, массив или иммутабельный объект) в конструкторе объекта сразу видима после завершение конструктора. Это позволяет быть уверенным, что иммутабельный объект корректно публикуется между потоками, даже в присутствии гонки, без дополнительной синхронизации.
  
  === *Вычисление hashCode у java.lang.String имеет data race — Вас это не пугает?*
  
  Нет, потому что поле *hash* в классе *String* имеет тип *int*. JMM гарантирует, что запись в 32-битную переменную всегда будет атомарна. Поэтому мы  можем в нем увидеть либо 0, либо корректно вычисленное значение хэш-кода. У нас нет необходимости сразу увидеть вычисленный хэш-код. Это поле является всего лишь оптимизацией кэширования вычисления. Если поток увидет в нем 0, то просто еще раз сделает вычисление. Это решение видится вполне логичным инженерным компромиссом.
  
  === *Объясните смысл выражения «data race free программа является sequential consistent».*
  
  Программа является *sequential consistent*, если ее действия на всех процессорах выполняются в каком-то последовательном порядке, и операции на каждом процессоре выполняются в программном порядке.  *Data race free* означает, что в программе нет одновременных чтений-записей в одну ячейку памяти. Так как у нас нет конфликтов между чтениями и записями, то мы можем построить последовательный порядок, в котором выполняются операции. Внутри же процесса операции могут быть перестановлены как угодно. При этом программный порядок не нарушится, а перестановки не будут иметь эффект на другие процессоры.
  
  === *Что такое ordering, visibility, atomicity, happend-before, mutual exclusion на примере volatile?*
  
  *Ordering* - компилятору запрещено переставлять инструкции, которые работают с volatile переменными. То есть мы можем быть уверенными, что инструкции до volatile выполнились, а после него еще не начались. 
  
  *Visibility* - записи в volatile переменные видимы для всех последующих чтений.
  
  *Atomicity* - записи в volatile переменные атомарны в независимости от разрядности. Т.е записи volatile long и double поля всегда будут атомарны, в отличие от "голых" long и double.
  
  *Happens-before* - с практической точни зрения это комбинация видимости и упорядочивания. Все записи в volatile поля имеют отношение *happens-before* по отношению к чтениям.
  
  *Mutual exclusion* - volatile не гарантирует взаимного исключения. То есть операции с volatile полями не блокируют друг друга. volatile гарантирует, что чтение переменной увидит последнюю запись в нее, но не засчет взаимного исключения. 
  
  === *Что такое ordering, visibility, atomicity, happend-before, mutual exclusion на примере synchronized?*
  
  *Ordering* - компилятору запрещено переставлять инструкции в критической секции, выделенной с помощью *synchronized* с остальными инструкциями. То есть все операции выполняются до входа в критическую секцию и ни одна не начинается после ее окончания.
  
  *Visibility* - записи в переменные внутри критической секции видимы для последующих чтений внутри этой же критической секции.
  
  *Atomicity* - *synchronized* организуюет критической секцию. Все действия в критической секции выполняются только одним процессом, поэтому они являются атомарными. Конечно, при условии, что доступ к данным осуществляется только в критической секции.
  
  *Happens-before* - вход в *synchronized* блок создает отношение *happens-before* выходу из него.
  
  *Mutual exclusion* - *synchronized* создает критическую секцию и гарантирует взаимное исключение.
  
  === *Что такое ordering, visibility, atomicity, happend-before, mutual exclusion на примере AtomicInteger?*
  
  У *AtomicInteger* такие же гарантии на *ordering*, *visibility* и *happens-before*, как и у *volatile*, потому что поле *value* внутри него объявлено как *volatile*.
  
  *Atomicity* - чтение и запись в `AtomicInteger` атомарны. Атомарность достигается засчет механизма CAS. CAS-инструкции позволяют атомарно обновить ячейку памяти или получить ошибку в случае, если состояние ячейки изменилось во время операции. В случае конфликта выполняется повтор операции до ее успешного выполнения.
  
  *Mutual exclusion* - `AtomicInteger` не гарантирует взаимного исключения. Несколько процессов могут одновременно читать его значение, но писать может только один.
  
  === *Атомарно ли ++ для volatile переменной?*
  
  Нет, так как в реальности ++ представляет из себя 3 инструкции: чтение, инкремент и запись. *volatile* гарантирует только атомарность одиночной записи (мы не увидим шум внутри поля), но не атомарность набора операций. То есть никто не запрещает 2 процессам прочитать одинаковое значение переменной, сделать инкремент и записать его в память. В этом случае мы получим "потерянную запись". 
  
  ==  Базовое API, примитивы/конструкции
  
  === *Thread.getState() возвращает экземпляр Thread.State. Какие возможны значения?*
  
  * *NEW* - поток был создан, но еще не стартовал; 
  * *RUNNABLE* - поток выполняется. Этот статус не обязательно значит, что поток выполняет код. Это всего лишь значит, что поток доступен планировщику потоков для выбора потока на исполнение;
  * *WAITING* - поток ждет на мониторе; Поток переходит в него вызовами методов  `wait()`, `join()` либо парковкой через `LockSupport.park()`
  * *TIME_WAITING* - поток ждет на мониторе с таймаутом; Те же самые методы, только  с таймаутом + `sleep`.
  * *BLOCKED* - поток заблокирован на мониторе; Поток переходит в него когда пытается войти в критическую секцию, но она уже занята другим потоком. 
  * *TERMINATED* - поток завершил выполнение. 
  
  === *Отличие Thread.start() и Thread.run()?*
  
  `Thread.start()` в отличие от `Thread.run()` переводит поток в состояние RUNNABLE и запускает код независимо от текущего потока. В случае же вызова `Thread.run()` код выполнит тот же поток, который вызвал этот метод. Семантически эти 2 метода совершенно различны: `run` отвечает за задачу, которую нужно выполнить независимо, а `start` за поднятие инфрастуктуры по выполнению этой задачи.
  
  === *Что происходит при вызове Thread.interrupt()?*
  
  Потоку, для которого вызвали этот метод, выставляется флаг того, что он прерван. Код, исполняющийся в этом потоке, может периодически проверять этот флаг на предмет того, что ему нужно завершить выполнение. Если поток в момент вызова `interrupt` спал, ждал, был заблокирован на мониторе или на I/O(InterruptibleChannel), то выбросится `InterruptedException` и флаг прерывания сбросится. Программист имеет возможность обработать `InterruptedException`, выполнить действия по безопасному завершению и решить, что делать дальше (пробросить исключение, восстановить статус прерывания или завершить работу).
  
  === *Что происходит при вызове Thread.stop()?*
  
  При вызове `Thread.stop` поток отпускает все мониторы, которые он держал,  выкидавает ошибку `ThreadDeath` и завершается принудительно.
  
  === *Почему Thread.stop()/destroy()/suspend()/resume() — deprecated?*
  
  Потому что они небезопасны. Поток может быть прерван в любой момент и обязан отпустить все блокировки. То есть например во время атомарного обновления структуры данных, поток может прерваться и структура окажется в поврежденном состоянии. Это неприемлимо. Для того, чтобы защититься в коде нужно ловить `ThreadDeath`, обрабатывать его и пробрасывать дальше. Но такой подход не практичен, сильно усложняет код и поддерживает плохую практику убивания ресурсов без их очистки.
  
  === *Перечислите все причины по которым может выскочить InterruptedException*
  
  