Backend
October 11, 2023

Многопоточное программирование в Java: основы работы с потоками

Что такое многопоточное программирование?

Представь, что ты делаешь домашнее задание по математике и одновременно слушаешь музыку. То есть ты выполняешь сразу два действия "параллельно". В программировании такая возможность тоже есть - запускать несколько задач одновременно в разных "потоках".

Зачем это нужно? Например, чтобы программа могла выполнять расчеты и показывать результат пользователю без задержек. Или загружать файл из интернета в фоновом режиме, пока пользователь работает с приложением. То есть многопоточность позволяет сделать программу более отзывчивой и эффективной.

Что представляет собой поток в Java?

Поток в Java - это последовательность команд, которая выполняется независимо от других потоков. Чтобы создать поток, нужно создать объект класса Thread или класса, который его расширяет.

Например:

Thread thread1 = new Thread(new Runnable() { 
public void run() {
// код потока 
} 
});

Здесь мы создали анонимный класс, реализующий интерфейс Runnable, и передали его в конструктор Thread.

Другой способ - расширить класс Thread:

class MyThread extends Thread { 
public void run() { 
// код потока 
} 
}

А затем создать объект:

MyThread thread2 = new MyThread();

В обоих случаях метод run() содержит код, который будет выполняться в потоке.

Как запустить и остановить поток в Java?

Чтобы запустить поток, нужно вызвать метод start():

thread1.start();

Это запустит выполнение метода run() в отдельном потоке.

Чтобы остановить работающий поток, используй метод interrupt():

thread2.interrupt();

Это прервет выполнение потока.

Можно установить приоритет для потока, чтобы он выполнялся быстрее других:

thread1.setPriority(Thread.MAX_PRIORITY);

Приоритеты бывают от 1 (минимальный) до 10 (максимальный).

Как синхронизировать потоки в Java?

Поскольку потоки работают параллельно, возможны проблемы синхронизации. Например, два потока одновременно изменяют одну переменную, и значение получается неправильное.

Чтобы этого избежать, используй ключевое слово synchronized:

synchronized(lock) { 
// критическая секция, доступная только для одного потока за раз 
}

Здесь lock - это объект-замок для синхронизации.

Например:

Object lock = new Object();
synchronized(lock) { 
x = x + 1;
}

Такую "критическую секцию" может выполнять только один поток за раз. Другие потоки будут ждать, пока секция освободится.

Что такое мьютексы в Java?

Мьютексы - это еще один способ синхронизации потоков. Мьютекс (mutex) представляет собой "замок", который может захватить только один поток.

Например:

Mutex mutex = new Mutex();
mutex.lock(); // захват замка 
// критическая секция 
mutex.unlock(); // освобождение замка

В отличие от synchronized блоков, мьютексы позволяют более гибко управлять доступом к ресурсам.

Где применяется многопоточность?

Многопоточность очень полезна в приложениях, где нужно:

  • Выполнять фоновые операции (загрузки, обработка файлов)
  • Обрабатывать много пользовательских запросов параллельно (веб-сервер)
  • Делать параллельные вычисления (научные приложения)

То есть везде, где нужно совмещать выполнение нескольких задач одновременно, можно применить многопоточное программирование.

Итог

Многопоточное программирование позволяет создавать более эффективные и отзывчивые программы за счет параллельного выполнения кода. Мы рассмотрели основные способы создания и управления потоками в Java, а также варианты синхронизации для решения возможных проблем. Многопоточность широко используется в современных приложениях.