Короткий ответ
Первый способ — создать подкласс Thread и переопределить метод run(). Второй — реализовать интерфейс Runnable и передать экземпляр задания в конструктор Thread. Запускает поток всегда метод start(): именно он создаёт новый поток и внутри него вызывает run().
Как это работает подробнее
Наследование от Thread смешивает задачу («что делать») с потоком («где выполнять») и расходует единственное место под наследование. Реализация Runnable считается предпочтительной: Java поддерживает только одиночное наследование, а интерфейс такой проблемы не создаёт; один и тот же объект Runnable можно передать в несколько потоков или в пул.
Родственный интерфейс Callable<T>: метод call() возвращает результат и может бросать проверяемые исключения в отличие от void run(). Задачи Callable выполняются не через new Thread(...), а через ExecutorService.submit(), который возвращает Future<T> для получения результата.
Пример кода
public class ThreadCreation {
public static void main(String[] args) {
// Способ 1: наследование от Thread
new MyThread().start();
// Способ 2: реализация Runnable
Runnable task = () -> System.out.println("Задача в потоке");
new Thread(task).start();
}
static class MyThread extends Thread {
@Override
public void run() {
System.out.println("Работает поток " + getName());
}
}
}Что использовать на практике
- Runnable — стандартный выбор: задача отделена от потока, её можно переиспользовать в пулах.
- Thread — допустим для коротких демонстраций, когда нужно менять поведение самого потока.
- Callable — бери, когда нужен результат или возможны проверяемые исключения; запускай через ExecutorService.
Подводные камни
- Вызов
run()напрямую не создаёт новый поток — код выполнится в текущем потоке; нуженstart(). - Унаследовавшись от
Thread, ты теряешь возможность наследоваться от другого полезного класса.
Как отвечать на собеседовании
- Назови два способа: extends Thread и implements Runnable → покажи код с start() → объясни, почему Runnable предпочтительнее (нет множественного наследования, задача отделена от потока) → добавь Callable и ExecutorService.submit() как способ получить результат.