— Привет, Амиго! Вчера мы обсудили преимущества и удобства, которые несет с собой многонитиевость (multithreading). Теперь пора взглянуть и на минусы. А они, к сожалению, не маленькие.
Раньше мы смотрели на программу, как на набор объектов, которые вызывают методы друг друга. Теперь все стало немного сложнее. Программа – это скорее набор объектов, по которым лазает несколько «маленьких роботиков» – нитей – и выполняют команды, содержащиеся в методах.
Формально – второе не отменяет первое. Это все еще объекты, и они все еще вызывают методы друг у друга. Но нужно не забывать, что нитей – несколько, и каждая нить выполняет свою работу – свое задание.
Программа становится сложнее. Разные нити меняют состояние разных объектов в соответствии с задачей, которую каждая из них выполняет. И могут мешать друг другу.
Но самое страшное происходит глубоко внутри Java-машины. Как я уже рассказывала, видимая одновременность работы нитей достигается за счет того, что процессор постоянно переключается с одной нити на другую. Переключился на нить, поработал 10 миллисекунд, переключился на следующую нить, там поработал 10 миллисекунд и так далее. И тут возникает проблема: переключение может произойти в самый неподходящий момент. Пример:
| Код первой нити | Код второй нити |
|---|---|
|
|
| Ожидаемый вывод на консоль |
|---|
| Коле 15 лет Лене 21 год |
| Итоговый порядок | Код первой нити | Код второй нити |
|---|---|---|
|
|
|
| Реальный вывод на консоль |
|---|
| Коле Лене 15 21 лет год |
Или вот еще пример:
| Код | Описание |
|---|---|
|
Метод swap меняет местами значения переменных name1 & name2. |
Что же будет если его вызывать из двух нитей одновременно?
| Итоговый порядок | Код первой нити | Код второй нити |
|---|---|---|
|
|
|
| Итог |
|---|
| Обе переменных имеют значение «Лена». Объект «Оля» был перезатерт и потерян. |
— Кто бы мог подумать, что при элементарном присваивании возможны такие ошибки?
— Да, но для этой проблемы есть решение. Но об этом немного позже – у меня горло пересохло.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ