JavaRush/Курсы/Java Core/Проблемы многопоточности: обращение к общему ресурсу

Проблемы многопоточности: обращение к общему ресурсу

Открыта

— Привет, Амиго! Вчера мы обсудили преимущества и удобства, которые несет с собой многонитиевость (multithreading). Теперь пора взглянуть и на минусы. А они, к сожалению, не маленькие.

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

Формально – второе не отменяет первое. Это все еще объекты, и они все еще вызывают методы друг у друга. Но нужно не забывать, что нитей – несколько, и каждая нить выполняет свою работу – свое задание.

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

Но самое страшное происходит глубоко внутри Java-машины. Как я уже рассказывала, видимая одновременность работы нитей достигается за счет того, что процессор постоянно переключается с одной нити на другую. Переключился на нить, поработал 10 миллисекунд, переключился на следующую нить, там поработал 10 миллисекунд и так далее. И тут возникает проблема: переключение может произойти в самый неподходящий момент. Пример:

Код первой нити Код второй нити
System.out.print ("Коле"); System.out.print (" "); System.out.print ("15"); System.out.print (" "); System.out.print ("лет");
System.out.println ();
System.out.print ("Лене"); System.out.print (" "); System.out.print ("21"); System.out.print (" "); System.out.print ("год");
System.out.println ();
Ожидаемый вывод на консоль
Коле 15 лет
Лене 21 год
Итоговый порядок Код первой нити Код второй нити
System.out.print ("Коле");
System.out.print ("Лене"); System.out.print (" ");
System.out.print (" "); System.out.print ("15");
System.out.print ("21"); System.out.print (" ");
System.out.print (" "); System.out.print ("лет"); System.out.println ();
System.out.print ("год"); System.out.println ();
System.out.print ("Коле");
//исполняется другая нить
//исполняется другая нить
System.out.print (" "); System.out.print ("15"); //исполняется другая нить
//исполняется другая нить
System.out.print (" "); System.out.print ("лет"); System.out.println ();
//исполняется другая нить
//исполняется другая нить
//исполняется другая нить
System.out.print ("Лене"); System.out.print (" ");
//исполняется другая нить
//исполняется другая нить
System.out.print ("21"); System.out.print (" ");
//исполняется другая нить
//исполняется другая нить
//исполняется другая нить
System.out.print ("год"); System.out.println ();
Реальный вывод на консоль
Коле
Лене
15
21
лет
год

Или вот еще пример:

Код Описание
class MyClass {
    private String name1 = "Оля";
    private String name2 = "Лена";
    public void swap() {
        String s = name1;
        name1 = name2;
        name2 = s;
    }
}
Метод swap меняет местами значения переменных name1 & name2.

Что же будет если его вызывать из двух нитей одновременно?

Итоговый порядок Код первой нити Код второй нити
String s1 = name1; //Оля
name1 = name2; //Лена
String s2 = name1; //Лена(!)
name1 = name2; //Лена
name2 = s1; //Оля
name2 = s2; //Лена
String s1 = name1; name1 = name2;
//исполняется другая нить
//исполняется другая нить
name2 = s1;
//исполняется другая нить
//исполняется другая нить
//исполняется другая нить
String s2 = name1; name1 = name2;
//исполняется другая нить
name2 = s2;
Итог
Обе переменных имеют значение «Лена».
Объект «Оля» был перезатерт и потерян.

— Кто бы мог подумать, что при элементарном присваивании возможны такие ошибки?

— Да, но для этой проблемы есть решение. Но об этом немного позже – у меня горло пересохло.

Комментарии (245)
  • популярные
  • новые
  • старые
Для того, чтобы оставить комментарий Вы должны авторизоваться
TimJohnzz
Уровень 19
3 октября, 15:03
ну тут либо join(), либо volatile для полей, либо отдельные обьекты для взаимодействия с ПОТОКАМИ(не нитями, почему опять стали нити??)
Grigoryvvv
Уровень 28
Expert
22 сентября, 09:46
22.09.2026 / 27 уровень Стоит уточнить для понимания, что такая проблема, с использование разными нитями одних полей объекта, возникнет если все нити используют один и тот же объект
MyClass obj = new MyClass();

Thread t1 = new MyThread(obj);
Thread t2 = new MyThread(obj);

t1.start();
t2.start();
а также, такая проблема возникнет при использовании static полей. Если же поля не static и каждая нить будет использовать свой новый объект, то поля не перепутаются и не перезатрутся, т.к. не будут использованы другими нитями:
MyClass obj1 = new MyClass();
MyClass obj2 = new MyClass();

Thread t1 = new MyThread(obj1);
Thread t2 = new MyThread(obj2);

t1.start();
t2.start();
Карен Абазов
Уровень 36
3 июня, 22:23
коммент от 4 мая 2026 надеюсь я не один тут остался....
Сайфер
Уровень 51
7 июля, 19:27
Не один
Win32Trojan
Уровень 2
22 августа, 12:37
А я надеюсь ты не забросил )
TimJohnzz
Уровень 19
3 октября, 15:02
только вперед!
Michael's
Уровень 32
17 марта, 08:05
мартовский коммент
C0N5P1RACY QA Automation Engineer
4 февраля, 18:24
Февральский коммент?)
Exaltyr777
Уровень 25
23 сентября 2025, 17:36
Многопоточность: 😇 Малопоточность: 💀
Закирка Джава МОНСТРШколяр в Школа
31 октября 2025, 06:35
ватахел май бразе
Anonymous #3585174
Уровень 33
27 августа 2025, 06:13
Like
Anonymous #3443159
Уровень 29
22 апреля 2025, 14:41
Объект Оля разве не остался в S1 ???
Marat Safiianov
Уровень 38
29 апреля 2025, 09:24
String s - это переменная метода, она хранится пока выполняется метод, в котором она объявлена. После выполнения метода переменная подлежит удалению.
4 марта 2025, 12:38
горло пересохло))
KPR500
Уровень 33
1 марта 2025, 22:15
Мартовский коммент ?
4 марта 2025, 12:37
он самый