anchor.diff:  
   === *Что из данных вызовов создает happend-before: Thread.sleep(), Thread.join(),Thread.yield(), Thread.start(), Thread.run(), Thread.isAlive(), Thread.getState()?*
   
  -Happens-before создают `Thread.start()`, `Thread.join()` и `Thread.isAlive()`.
  - `Thread.start()` создает hb между вызовом метода и первым действием в потоке,
  -а `Thread.join()` и `Thread.alive()` между последним действием в потоке и
  -вызовом метода.
  +Happens-before создают `Thread.start()`, `Thread.join()` и `Thread.isAlive()`. `Thread.start()` создает hb между вызовом метода и первым действием в потоке, а `Thread.join()` и `Thread.alive()` между последним действием в потоке и вызовом метода.
   
   === *В чем разница между Thread.sleep() и Thread.yeild()?*
   
   Это совершенно разные действия. 
   
  -* `Thread.sleep` переводит поток в состояние `TIMED_WAITING` и блокирует его
  -до окончания времени сна.
  -* `Thread.yeild` всего лишь является подсказкой планировщику о том, что у
  -потока можно забрать квант времени. Поток при этом остается в состоянии
  -`RUNNABLE`. Реализации JVM вольны игнорировать вызовы `Thread.yeild()` и
  -практическая ценность этого метода довольно сомнительна.
  +* `Thread.sleep` переводит поток в состояние `TIMED_WAITING` и блокирует его до окончания времени сна.
  +* `Thread.yeild` всего лишь является подсказкой планировщику о том, что у потока можно забрать квант времени. Поток при этом остается в состоянии `RUNNABLE`. Реализации JVM вольны игнорировать вызовы `Thread.yeild()` и практическая ценность этого метода довольно сомнительна.
   
   === *В чем проблема с Double Checked Locking? Как все-таки сделать потокозащищенный ленивый синглетон с дешевым доступом?*
   
  -Проблема в DCL в том, что это небезопасная идиома. Изначально придуманная как
  -оптимизация производительности она ведет к тому, что синглтон в реальности не
  -будет синглтоном.
  -
  -Например, простой синглтон:
  +Проблема в DCL в том, что это небезопасная идиома. Изначально придуманная как оптимизация производительности она ведет к тому, что синглтон в реальности не будет синглтоном. Например, простой синглтон:
   
   [source,java]
   ----
  
positive.code: * Возможность "практически одновременно" выполнять несколько задач;
  * Лучшая "отзывчивость" систем, для которых более важен быстрый ответ, а не 
  общее количество выполненной работы;
  * Более быстрое выполнение задач, которые не ограничены процессорным временем.
  Скажем, у нас есть n задач, которые выполняют I/O (чтение из сети) и они не 
  связаны между собой. В этом случае мы можем их параллельно запустить и 
  обрабатывать результаты каждой задачи, только когда они будут готовы. Если бы 
  эти задачи выполнялись параллельно, то мы бы тратили процессорное время на 
  задержки сети. 
  
  ==  «Железо»
  
  
negative.code: * L3 - кэш на процессоре, общий для всех ядер. Скорость доступа порядка 20 нс.
  Может быть достаточно большим (8-32 MB). 
  
  Появление кэшей вызывало тот факт, что скорость работы процессора начала становится намного больше скорости доступа к памяти. Поэтому для того, чтобы избежать огромных задержек по доступу к данным из основной памяти (порядка 60 нс), производителями процессоров были добавлены кэши на процессорах для быстрого выполнения операций над "горячими" данными. 
  
  === *Что такое Memory wall?*
  
  _Memory wall_ - это термин, описавающий ограничение производительности вычислительных систем скоростью доступа к памяти. Несмотря на то, что частота процессоров в 70-90-е годы увеличивалась в 2 раза каждые 2 года, скорость доступа к памяти не увеличивалсь с такой же степенью. В итоге производительность системы в целом упиралась в производительности памяти, так как процессоры не могли работать на своей полной вычислительной мощности.
  
  === *Что такое Memory Hierarchy?*
  
  _Memory Hierarchy_ - термин для описания производительности систем хранения данных. Чем ниже уровень иерархии, тем дешевле цена системы хранения и больше время доступа к ней. Обычно выделяют 4 уровня:
  
  * Регистры и кэши процессора (скорость доступа порядка 100-500 Гб/c)
  * Оперативная память (скорость доступа порядка 1-10 Гб/c)
  * Диски (скорость доступа порядка 100-500 Мб/c)
  * Третичные хранилища (скорость доступа порядка 10-100 Мб/c)
  
  === *Что такое Cache line? В виде каких эффектов проявляется?*
  
  _Cache line_ - блок данных(обычно 64 байт), в котором передаются данные между процессором и оперативной памятью. Когда процессору нужно прочитать данные по конкретному адресу из опертивной памяти, он вместо 1 байта читает сразу блок данных и кладет этот блок в кэш. Такая оптимизация хорошо работает в случае, если данные, над которыми работает процессор, обладают хорошей локальностью. Тогда при следующем
  чтении данные уже будут в кэше и процессору не нужно будет делать дорогой запрос в оперативную память.
  
  === *Что такое False sharing? Плохо это или хорошо? Как с этим бороться?*
  
  _False sharing_ - эффект при котором данные, не связанные с друг другом, попадают в одну кэш-линию. В итоге когда изменяется одна из частей данных в кэш-линии, вся линия инвалидируется. Это плохой эффект, так как он может вызывать трешинг (thrashing) - постоянную подгрузку и инвалидацую данных их кэша. Например, часто читаемые данные могут попать на одну линию с часто записываемыми. При каждой записи линия будет инвалидироваться из кэша вместе с часто читаемыми данными, хотя сами данные не менялись.
  
  Бороться можно с помощью техники паддинга (padding). Часто читаемые данные выравниваются по модулю длины кэш-линии с помощью фиктивных байтов. В итоге исключается вариант, когда вместе с ними на кэш-линию попадают "случайные" данные.
  
  === *Что такое Memory padding?*
  
  _Memory padding_ - это техника выравнивая структуры данных по границам читаемого процессором размера слова. Она позволяет быть уверенным, что данные всегда попадут на одну кэш-линию и займут ее экслюзивно. Это позволяет избежать трешинга кэша, в случае, если на линию попадают не соотносящиеся друг с другом данные.
  
  === *Что такое Cache pollution? Плохо это или хорошо? Как с этим бороться?*
  
  _Cache pollution_ - эффект при котором, происходит трешинг кэшей из-за того, что активные данные не имеют локальности. Если данные на находятся на одной кэш-линии, то при чередующем обращении к 1-му и 2-му набору данных, кэш будет постоянно инвалидировать и подгружать данные.
  Это плохой эффект, так как он может привести к заметному падению производительности приложения без видимой для программиста причины. 
  Бороться можно изменением подхода к обработке данных. Идея заключается в том, чтобы в один период времени работать только с "горячими" данными в кэше и начинать работу со следующим набором данных только после того, как первый больше не нужен.
  
  === *Что такое Cache miss? Плохо это или хорошо? Как с этим бороться?*
  
  _Cache miss_ - ситуация, когда запрашиваемого блока данных нет в кэше. В общем случае, это не является плохим эффектом, так если данные запрашиваются первый раз, то они все равно должны быть загружены в кэш. Процессоры часто спекулируют о паттернах доступа данных и вместе с запрашиваемым блоком данных кэшируют больший блок данных, полагаясь на локальность данных. Поэтому для близко лежащих данных промахов не будет. Проблема возникает, когда промахов становится очень много. Это значит, что данные не локальны и кэш не может эффективно предпогружать
  данные. Бороться с промахами можно с помощью изменения расположения данных в памяти (большая локальность), изменением патернов доступа к данным (избегать трешинга), тюнингом размера кэша.
  
  === *В чем разница между SMP и NUMA? Как это сказывается на программах?*
  
  SMP-системы имеют одну большую память, которая распределяется между процессорами. Процессоры общаются с памятью через глобальную шину данных. В NUMA-системах, в свою очередь, для каждого процессора есть своя локальная память и локальная шина. Это сильно снижает трафик на шинах в случае если процессоры работают над независимыми данными. В операционной системе должна быть поддержка NUMA-систем (специальный аллокатор памяти, привязка программ к процессору), иначе производительность системы будет намного хуже, чем SMP из-за отсуствия локальности данных и, следовательно, большой цены (~100 нс) последующей загрузки данных не из локальной памяти для процессора. 
  
  === *В чем разница между Multicore и Multisocket?*
  
  * Multicore - это один процессор с несколькими ядрами.
  * Multisocket - это несколько одноядерных процессоров.
  
  Multisocket системы дороже, чем Multicore (нужен отдельный сокет на каждый процессор. А каждый процессор в свою очередь является чипом). Они лучшеработают, если процессоры сильно не зависимы от друг друга (обрабатывают разный набор данных). Тогда можно избежать трешинга L3-кэшей, так как они у процессоров раздельные. В общем случае Multicore системы работают лучше, так как программы обычно не настолько требовательны к ресурсам, чтобы потреблять всю вычислительную мощность ядра/процессора. При этом засчет L3 кэша переключение программ с ядро на ядро в multicore-процессорах происходит быстрее.
  
  === *Что такое Thread affinity? Можно ли сделать в Java?*
  
  _Thread affinity_ - это возможность привязать выполнение потока к определенному ядру. Это является оптимизацией производительности в мультипроцессорных системах. Ее цель - увеличить процент "попадания" в кэш при доступе к данным. Смысл оптимизации в извлечении пользы из наблюдения о том, что большинство потоков обычно работают с одним и тем же набором данных. То есть после того как поток прервется планировщиком и заново получит квант времени, ему лучше выполнится на том же ядре, так как скорее всего оно уже будет содержать нужные данные в своем кэше. Из Java напрямую сделать нельзя, но есть возможность сделать через JNA/JNI, если известна целевая платформа.
  
  === *Что такое Inter Thread Parallelism? Task Parallelism?*
  
  Честно говоря, термины мне не известны. Возможно, имеется ввиду _hyper threading_?
  
  Это технология симуляции нескольких процессоров для операционной системы засчет дублирования вычислительных регистров. Операционная система планирует 2 потока на "виртуальные" процессоры, и кладет данные в регистры. Процессор же в свою очередь выполняет инструкции последовательно. Идея в том, чтобы уменьшить цену переключения потоков, передавая сразу 2 потока инструкций на процессор. Процессор, имея больше информации о потоке инструкций, может делать больше спекулятивных оптимизаций.
  
  === *Что такое Branch Prediction?*
  
  _Branch Prediction_ - это предсказание процессором перехода на определенную ветку выполнения кода. Так как современные процессоры работают конвеером и переходят к следующей инструкции до ее выполнения, то очень неэффективно ждать, пока определится результат условия. Поэтому процессоры спекулятивно выполняют одну из веток и только потом определяют, была догадка правильной или нет. В случае, если процессор не угадывает ветку выполнения, то он возвращается назад и начинает конвеер сначала.
  
  === *Что такое Speculative Execution?*
  
  _Speculative Execution_ - это оптимизация, при которой выполняется некоторая часть кода до проверки необходимости ее выполнения. Идея заключается в наблюдении о том, что многие условия на практике перенаправляют выполнению на одну ветку, и очень редко на другую. Пример - проверка кода ошибки. В большинстве случаев операция завершится успешно. Если процессор не делал бы спекулятивное выполнение, то он бы вынужден был всегда ждать выполнения последней команды перед условием. А так он может сразу переходить к ветке с успешным выполнением, не дожидаясь конца выполнения операции. В редком случае ошибки процессор просто вернется к условию и выполнит ветку обработки ошибки.
  
  === *Сравните с точки зрения программиста — машину с четырехядерным процессором и двумя двухядерными процессорами*
  
  В общем, для программиста нет никакой разницы. ОС в обоих случаях будет показывать 4 доступных процессора. Единственный случай - это если имеется 2 большие независимые программы. Тогда имеет смысл запустить их на разных физических процессорах, чтобы избежать трешинга L1-L2 кэша.
  
  === *Напишите программу, которая демонстрирует False sharing*
  
  См. https://github.com/arteam/100-Java-Concurrency-questions/tree/master/false-sharing[false-sharing]
  
  Бенчмарк измеряет одновременное чтение и запись полей объекта в памяти. По предположению в отстуствие паддинга должен проявляться эффект false sharing. То есть записи в поле y должны делать кэш-линию инвалидной и вследствии чего поле x будет читаться из памяти, а не из кэша.
   
  Из результатов бенчмарка видно, что в случае расположения полей объекта на одной кэш-линии пропускная способность чтений в 3 раза хуже, чем в случае, когда JVM выравнивает поле x по линии кэша.
  
  ----
  c.g.a.b.FalseSharingBenchmark.contended:read      thrpt   10   60.870 ±  5.394  ops/us
  