Введение
Прежде, чем узнать про потоки Java, давайте заглянем в недалёкое будущее. Представьте, что вы подали резюме и прошли собеседование. Вас и пару дюжин будущих коллег пригласor на работу в большую Software-компанию. Среди прочих хлопот нужно подать бумажные documentы для трудоустройства уставшему сотруднику HR-отдела.
Whatбы ускорить процесс, претендентов на должность можно разделить на две группы и распределить их между двумя HR-менеджерами (если таковые есть в компании). В результате мы получаем ускорение процесса за счёт параллельной (
parallel) работы по оформлению.
Если же кадровик в компании один, то придётся How-то выкручиваться. Например, можно снова- таки разбить всех на две группы, например, собеседовать поочерёдно девушек и юношей.
Или по другому принципу: так How в нижней группе больше народа, будем чередовать на одного юношу двух девушек.
Такой способ организации работы называется
многопоточным. Наш утомлённый кадровик переключается на разные группы для оформления из них очередного сотрудника. Групп, может быть, одиннадцать, а кадровиков – четыре. В этом случае многопоточная (
multithreading) обработка будет происходить параллельно несколькими HR-ами, которые могут брать очередного человека из любой группы для обработки его documentов.
Процессы
Процессом (
process) в данном случае будет организация работы приёма documentов. В организации можно выделить несколько процессов: бухгалтерский учёт, разработка ПО, встречи с клиентами, работа склада и т. д. На каждый процесс выделены ресурсы: помещение, сотрудники для его исполнения. Процессы изолированы друг от друга: у кадровиков отсутствует доступ в бухгалтерскую базу, а менеджеры по работе с клиентами не бегают по складу. Если процесс должен получить доступ к чужим ресурсам, необходимо наладить межпроцессное взаимодействие: служебные записки, совместные совещания.
Потоки
Работа в процессе организована в виде потоков (
java thread
). Для отдела кадров, поток – это организация работы по обслуживанию группы. На самой первой картинке – один поток, последующих трёх – два. Внутри процесса потоки могут выполняться параллельно – два кадровика принимают две or более группы будущих сотрудников. Взаимодействие кадровиков с группами – обработку потоков внутри процесса – называют
синхронизацией потоков. На рисунках оформления одним кадровиком двух групп видны показаны способы: равномерный (девушка – юноша – девушка – юноша) и с разными приоритетами (две девушки чередуются с одним юношей). Потоки имеют доступ к ресурсам процесса, к которому они относятся: группам к кадровику даны образцы бланков заявлений, ручки для заполнения documentов. Но если потоки взаимодействуют с общими для них вещами – то возможны казусы. Если кадровик попросит крикнуть Name последнего человека в очереди – то, в случае с двумя группами, он не уверен заранее, что услышит женское Name or мужское. Подобные конфликты доступа к данным, блокировки и способы их разрешения – очень важная тема.
Состояния потока
Каждый поток пребывает в одном из следующих состояний (state):
- Создан (
New
) – очередь к кадровику готовится, люди организуются.
- Запущен (
Runnable
) – наша очередь выстроилась к кадровику и обрабатывается.
- Заблокирован (
Blocked
) – последний в очереди юноша пытается выкрикнуть Name, но услышав, что девушка в соседней группе начала делать это раньше него, замолчал.
- Завершён (
Terminated
) — вся очередь оформилась у кадровика и в ней нет необходимости.
- Ожидает(
Waiting
) – одна очередь ждёт сигнала от другой.
Организация потоков и их взаимодействие – это основа эффективной работы процессов.
Вернемся в IT-мир
В XXI веке многопоточное и параллельное выполнение стало актуальным. С 90-х годов прошлого века многозадачные операционные системы Windows, MacOS и Linux прочно обосновались на домашних компьютерах. В них часто можно встретить четырёх- и более ядерные процессоры. Число параллельных блоков GPU-видеокарт уже перевалило за тысячу. Популярные программы пишутся с учетом многопоточности (multithreading), например, современные версии ПО обработки графики, видео or оперирующих большим объемом данных: Adobe Photoshop, WinRar, Mathematica, современные игры. Многопоточность Java – очень важная, востребованная и сложная тема. Поэтому в курсе JavaRush встречается много задач, чтобы разобраться с ней очень хорошо. Java-примеры на многопоточность помогут освоить основные нюансы и тонкости этой области, синхронизации работы потоков.
Процесс
Process (процесс) – выполняющийся экземпляр программы, которому Операционная Система (ОС) выделила память, процессорное время/ядра и прочие ресурсы. Важно, что память выделяется отдельно, addressные пространства различных процессов недоступны друг другу. Если процессам необходимо обмениваться данными, они могут это сделать с помощью файлов, каналов и иных способов межпроцессного взаимодействия.
Поток
Java
Thread
(поток). Иногда, чтобы не путать с другими классами Java –
Stream
и подобными, потоки Java часто переводят How нить. Они используют выделенные для процесса ресурсы и являются способом выполнения процесса. Главный поток выполняет метод
main
и завершается. При выполнении процесса могут порождаться дополнительные потоки (дочерние). Потоки одного процесса могут между собой обмениваться данными. Многопоточность Java требует учитывать синхронизацию данных, не забывайте об этом. В Java процесс завершается тогда, когда закончил работу последний его поток. Для фоновых задач поток можно запустить How демон (
daemon
), отличие которого от обычного в том, что они будут принудительно завершены при окончании работы всех не-
daemon
потоков процесса.
Первое многопоточное приложение
Существует более полудюжины способов создания потоков, в рамках JavaRush курса мы их подробно разберём. Для начала познакомимся с одним из базовых. Имеется специальный класс
Thread
в методе
run()
которого необходимо написать code, реализующий логику программы. После создания потока, можно запустить его, вызвав метод
start()
. Напишем демонстрационную программу, реализующую пример многопоточности Java.
class PeopleQueue extends Thread {
private String[] names;
PeopleQueue(String... names) {
this.names = names;
}
@Override
public void run() {
for (int i = 0; i < names.length; i++) {
System.out.println("Обработаны documentы: " + names[i]);
try {
sleep(500);
} catch (Exception e) {}
}
}
}
public class HR {
public static void main(String[] args) {
PeopleQueue queue1 = new PeopleQueue("Ivan","Сергей","Николай","Фердинанд","Basil");
PeopleQueue queue2 = new PeopleQueue("Мария","Людмила","Алиса","Карина","Olga");
System.out.println("Начали!");
queue1.start();
queue2.start();
}
}
Запустим программу. В консоли виден вывод messages главным потоком. Далее, каждый дочерний поток
queue1
и
queue2
поочередно выводят messages в общую для них консоль об очередном обработанном сотруднике. Один из возможных вариантов работы программы:
Начали!
Обработаны documentы: Мария
Обработаны documentы: Ivan
Обработаны documentы: Людмила
Обработаны documentы: Сергей
Обработаны documentы: Алиса
Обработаны documentы: Николай
Обработаны documentы: Карина
Обработаны documentы: Фердинанд
Обработаны documentы: Ольга
Обработаны documentы: Васorй
Process finished with exit code 0
Многопоточность в Java – тема трудная и многосторонняя. Умение писать code с использованием параллельных, многозадачных и многопоточных вычислений поможет вам эффективно реализовать задачи на современных многоядерных процессорах и кластерах, состоящих из множества компьютеров.
GO TO FULL VERSION