Как создать и начать новый поток в Java

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

1. Создание новой темы

В Java мы можем создать поток следующими способами:

  • Расширяя класс Thread
  • Реализуя интерфейс Runnable
  • Использование лямбда-выражений

1.1. Путем расширения класса Thread

Чтобы создать новый поток, расширьте класс с помощью Thread и переопределите метод run().

class SubTask extends Thread {public void run() {System.out.println("SubTask started...");}}

1.2. Реализация интерфейса Runnable

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

class SubTaskWithRunnable implements Runnable {public void run() {System.out.println("SubTaskWithRunnable started...");}}

1.3 Использование лямбда-выражений

Лямбда-выражения помогают создавать встроенные экземпляры функциональных интерфейсов и могут помочь сократить объем шаблонного кода.

Runnable subTaskWithLambda =() ->{System.out.println("SubTaskWithLambda started...");};

2. Создание новой темы

Начать новый поток в Java можно несколькими способами, давайте узнаем о них.

2.1 Использование Thread.start()

Метод Thread start() считается сердцем многопоточности. Без выполнения этого метода мы не можем начать новый поток. Другие методы также внутренне используют этот метод для запуска потока, за исключением виртуальных потоков.

Метод start() отвечает за регистрацию потока в планировщике потоков платформы и выполнение всех других обязательных действий, таких как распределение ресурсов.

Давайте на примере рассмотрим, как создать и запустить поток с помощью метода start().

class SubTask extends Thread {public void run() {System.out.println("SubTask started...");}}Thread subTask = new SubTask();subTask.start();

Мы можем использовать метод start() для выполнения потоков, созданных с помощью интерфейса Runnable.

class SubTaskWithRunnable implements Runnable {public void run() {System.out.println("SubTaskWithRunnable started...");}}Thread subTaskWithRunnable = new Thread(new SubTaskWithRunnable());subTaskWithRunnable.start();

Использование техники лямбда-выражений ничем не отличается от метода интерфейса Runnable.

Runnable subTaskWithLambda =() -> {System.out.println("SubTaskWithLambda started...");};Thread subTask = new Thread(subTaskWithLambda);subTask.start();

В конце концов, метод start() класса Thread — единственный способ начать новый поток в Java. Другие способы(кроме виртуальных потоков) внутренне используют метод start().

2.2 Использование ExecutorService

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

Пул потоков — это пул уже созданных потоков, готовых выполнить нашу задачу. В Java ExecutorService — это основа создания и управления пулами потоков. Мы можем отправить либо задачу Runnable, либо задачу Callable в ExecutorService, и он выполнит отправленную задачу, используя один из потоков в пуле.

Runnable subTaskWithLambda =() -> {System.out.println("SubTaskWithLambda started...");};ExecutorService executorService = Executors.newFixedThreadPool(10);executorService.execute(subTaskWithLambda);

Если мы создадим поток с помощью лямбда-выражения, то весь синтаксис станет намного проще.

ExecutorService executorService = Executors.newFixedThreadPool(10);executorService.execute(() ->{System.out.println("SubTaskWithLambda started...");});

2.3. Отложенное выполнение с ScheduledExecutorService

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

В следующем примере планируется выполнение задачи с задержкой в 10 секунд, и по завершении выполнения будет возвращен результат «завершено».

ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);ScheduledFuture<String> result = executor.schedule(() -> {System.out.println("Thread is executing the job");return "completed";}, 10, TimeUnit.SECONDS);System.out.println(result.get());

2.4 Использование CompletableFuture

CompletableFuture — это расширение Future API, представленное в Java 8. Оно реализует интерфейсы Future и CompletionStage. Оно предоставляет методы для создания, объединения и комбинирования нескольких Future.

В следующем примере CompletableFuture запустит новый поток и выполнит предоставленную задачу, используя методы runAsync() или supplyAsync() в этом потоке.

// Running RunnableJob using runAsync() method of CompletableFutureCompletableFuture<Void> future = CompletableFuture.runAsync(new RunnableJob());// Running a task using supplyAsync() method of CompletableFuture and return the resultCompletableFuture<String> result = CompletableFuture.supplyAsync(() -> "Thread is executing");// Getting result from CompletableFutureSystem.out.println(result.get());

2.5 Выполнение как виртуального потока

Начиная с Java 19, виртуальные потоки были добавлены как легковесные потоки, управляемые JVM, которые помогут в написании высокопроизводительных параллельных приложений.

Мы можем запустить задачу как виртуальный поток, используя недавно добавленные API:

Runnable runnable =() -> System.out.println("Inside Runnable");Thread.startVirtualThread(runnable);//orThread.startVirtualThread(() -> {//Code to execute in virtual threadSystem.out.println("Inside Runnable");});//orThread.Builder builder = Thread.ofVirtual().name("Virtual-Thread");builder.start(runnable); 

3. Заключение

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

Исходный код на Github

Прокрутить вверх