Найти тему

Чистый код. Конспект. Глава 18. Финал. Многопоточность 2.

Первая часть многопоточности были раньше. Эта глава считается дополнительной.

Заметки:

  1. Вычисление количества путей для потоков: (N*T)! / (N!)^T, где N — количество команд (сгенерированный байт-код), а T — количество потоков. Вообще впервые видела эту формулу, так что интересная информация.
  2. Используйте synchronized для уменьшения количества путей. Под путями понимается количество возможных вариантов, в каком порядке будет выполняться код. Например, если три потока А, Б и С, то возможные пути: АБС, АСБ, БАС, БСА, САБ, СБА.
  3. Атомарная операция — операция, выполнение которой не может быть прервано. Интересный факт: в Java a = 5 — атомарная операция, а b = 5L, не атомарная.
  4. Frame — для каждого вызова метода создается кадр с адресом возврата, значениями всех передаваемых параметров и локальных переменных из метода.
  5. Очень интересно переводить в байт-код и смотреть. Оказывается ++a — это 7 операций! И это, кстати, не атомарная операция.
  6. AtomicInteger всегда лучше synchronized.
  7. Серверная блокировка всегда лучше клиентской. Она сокращает дублирование, даёт более высокую производительность и снижает вероятность ошибки. И как бонус: единая политика использования, сокращает область видимости и всегда знаем где искать проблему.
  8. Старайтесь синхронизировать как можно меньше кода.
  9. Причины взаимной блокировки: взаимное исключение, блокировка с ожиданием, отсутствие вытеснения, циклическое ожидание.
  10. Взаимное исключение возникает когда несколько потоков должны использовать одни и те же ресурсы, а те ресурсы не могут использоваться несколькими потоками одновременно или существуют в ограниченном количестве. Типичный пример — подключение к БД.
  11. Как нарушить взаимное исключение: использовать ресурсы, поддерживающие многопоточку (AtomicInteger), увеличить количество ресурсов, чтобы оно достигло или превосходило количество конкурирующих потоков, проверять наличие всех свободных ресурсов перед попытками захвата.
  12. Блокировка с ожиданием — поток захватывает ресурс и не освобождает пока не захватит все остальные необходимые ресурсы и не завершит работу.
  13. Как нарушить блокировку с ожиданием — проверить перед захватом и освободить занятые ресурсы. Но тут есть проблемы: истощение (один поток и все ресурсы свободны), обратимая блокировка — все одновременно захватывают и освобождают ресурс.
  14. Отсутствие вытеснения — один поток не может отнимать ресурсы у другого потока. Если кто-то захватил ресурс, то второму потоку остается только ждать.
  15. Нарушение отсутствия вытеснения — если ресурс захвачен, то поток обращается к захватчику с просьбой освободить. Если тот ожидает другой ресурс, то освобождает. Из минусов: непросто реализовать.
  16. Циклическое ожидание — кот Мурзик ест из миски А. Кот Барсик ест из миски Б. Мурзик хочет попробовать корм из миски Б, а Барсик — из миски А. Оба кота ждут, когда освободятся миски.
  17. Нарушение циклического ожидания —заставляем потоки выделять ресурсы в постоянном порядке. При согласованном едином порядке захвата блокировки не будет. Но тут есть проблемы — порядок захвата может не соответствовать порядку использования. Например, вначале захватили и он потом не используется (Мурзик подошел к миске А и сидит возле неё, но не использует. Барсик ждёт). Еще минус, что ресурсы остаются заблокированными дольше необходимого. Также соблюдать фиксированный порядок возможно не всегда.
  18. Почти все стратегии приводят к ухудшению потоков или к интенсивному использованию процессора и ухудшению времени отклика. Бесплатный сыр бывает только в мышеловке.
  19. Тестирование методом Монте-Карло: это гибкие тесты, которые повторяем снова и снова со случайным изменением параметров. Также следует запускать тесты на машинах с разной нагрузкой.