Multithreading в Java: просто о сложном | OTUS

Курсы

Программирование
Разработчик Java
-20%
Fullstack разработчик JavaScript Архитектор высоких нагрузок Android-разработчик. Продвинутый курс
-20%
Android-разработчик. Базовый курс
-20%
Разработчик программных роботов (RPA) на базе UiPath и PIX
-20%
Алгоритмы для разработчиков
-20%
Agile Project Manager в IT
-20%
Разработчик на Spring Framework
-20%
iOS Разработчик. Продвинутый курс v 2.0.
-10%
PostgreSQL
-10%
Разработчик игр на Unity
-21%
VOIP инженер
-30%
Разработчик Java Enterprise MS SQL Server разработчик ReactJS/React Native-разработчик Разработчик голосовых ассистентов и чат-ботов Архитектура и шаблоны проектирования
Специализации Курсы в разработке Подготовительные курсы
+7 499 110-61-65

Multithreading в Java: просто о сложном

java_Deep_5-5020-bb8540.10_site.png

Принято считать, что многопоточность (multithreading) — одна из самых сложных тем в программировании. Давайте разберёмся, почему так много разработчиков делают ошибки при создании приложений, которые работают более чем в одном потоке.

Начнём с простого

Что такое поток в Java? Как и всё остальное, поток в Java — это объект. Создать объект потока совсем не сложно:

Thread thread = new Thread(); 

Что в этом объекте особенного? У него есть методы start() и run(). Например, если в методе main() вызвать у объекта потока метод start(), то через некоторое время у него будет вызван метод run(). И этот вызов будет иметь новый Stack и команды метода run() могут быть выполнены физически в одно и тоже время, что и команды метода main().

То есть… в другом потоке. И в этом первая сложность многопоточности: поток — это объект и в то же время поток — это последовательность команд. Команд метода run() объекта потока.

Вторая сложность многопоточности в непредсказуемости порядка некоторых событий. Допустим вы создали 10 новых потоков, пронумеровали их и вызвали у них методы start(). Будут ли методы run() этих объектов выполнены в той же последовательности, что вы задали при нумерации?

На самом деле нет. Значит, в какой последовательности будут выполнены методы run(), решает… операционная система. И у вас есть только очень опосредованные способы влияния на порядок выполнения (например, через приоритеты).

Взаимодействие потоков

Если у вас есть задача, которую можно сделать в отдельном потоке, не дожидаясь её завершения и игнорируя её результат (например: записать что-то в лог; послать по UDP данные; обработать запрос пользователя, прочитать ответ в базе и отправить пользователю), то многопоточность — легко и весело.

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

Ошибки приложения, которые при этом происходят, относят к одному из двух типов: race condition и memory consistency errors. Что это, и как с ними бороться, мы рассмотрим чуть позже.

Есть вопрос? Напишите в комментариях!

Не пропустите новые полезные статьи!

Спасибо за подписку!

Мы отправили вам письмо для подтверждения вашего email.
С уважением, OTUS!

Автор
0 комментариев
Для комментирования необходимо авторизоваться
🔥 Скидки до 50% на новые супер-интенсивы!
«Тестирование игр», «Data Engineer», «работа с протоколом BGP». Узнайте подробности в чате ➞