← Назад к вопросам

Как запустить поток

2.0 Middle🔥 191 комментариев
#Основы Java

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Ответ

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

В Java существует несколько способов создания и запуска потоков. Рассмотрим все основные подходы.

1. Использование Thread класса

Способ 1: Наследование от Thread

class MyThread extends Thread {
    private String name;
    
    public MyThread(String name) {
        this.name = name;
    }
    
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(name + ": " + i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                System.out.println("Thread interrupted");
            }
        }
    }
}

public class Main {
    public static void main(String[] args) {
        Thread thread1 = new MyThread("Thread-1");
        Thread thread2 = new MyThread("Thread-2");
        
        // Запуск потоков
        thread1.start();
        thread2.start();
        
        System.out.println("Main thread continues");
    }
}

Способ 2: Реализация интерфейса Runnable

class MyRunnable implements Runnable {
    private String name;
    
    public MyRunnable(String name) {
        this.name = name;
    }
    
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(name + ": " + i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                System.out.println("Thread interrupted");
            }
        }
    }
}

public class Main {
    public static void main(String[] args) {
        Thread thread1 = new Thread(new MyRunnable("Thread-1"));
        Thread thread2 = new Thread(new MyRunnable("Thread-2"));
        
        thread1.start();
        thread2.start();
    }
}

Способ 3: Lambda выражения (Java 8+)

public class Main {
    public static void main(String[] args) {
        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                System.out.println("Thread-1: " + i);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        });
        
        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                System.out.println("Thread-2: " + i);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        });
        
        thread1.start();
        thread2.start();
    }
}

2. Использование ExecutorService (рекомендуется)

Для управления пулом потоков лучше использовать ExecutorService:

import java.util.concurrent.*;

public class ExecutorExample {
    public static void main(String[] args) {
        // Создаём пул из 3 потоков
        ExecutorService executor = Executors.newFixedThreadPool(3);
        
        // Запускаем задачи
        for (int i = 1; i <= 5; i++) {
            final int taskId = i;
            executor.submit(() -> {
                System.out.println("Task " + taskId + " started by " + Thread.currentThread().getName());
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
                System.out.println("Task " + taskId + " completed");
            });
        }
        
        // Завершаем работу
        executor.shutdown();
        try {
            if (!executor.awaitTermination(10, TimeUnit.SECONDS)) {
                executor.shutdownNow();
            }
        } catch (InterruptedException e) {
            executor.shutdownNow();
        }
    }
}

3. Разные типы ExecutorService

// Пул с фиксированным числом потоков
ExecutorService fixed = Executors.newFixedThreadPool(4);

// Пул с одним потоком (последовательное выполнение)
ExecutorService single = Executors.newSingleThreadExecutor();

// Кешированный пул (растёт и сжимается по необходимости)
ExecutorService cached = Executors.newCachedThreadPool();

// Пул с графиком выполнения (ScheduledExecutorService)
ScheduledExecutorService scheduled = Executors.newScheduledThreadPool(2);
scheduled.scheduleAtFixedRate(() -> {
    System.out.println("Task executed every 2 seconds");
}, 0, 2, TimeUnit.SECONDS);

4. Важные правила

ВСЕГДА используй start(), а не run():

Thread thread = new Thread(() -> System.out.println("Hello"));

// ✅ ПРАВИЛЬНО - создаёт новый поток
thread.start();

// ❌ НЕПРАВИЛЬНО - выполняется в текущем потоке
thread.run();

5. Установка приоритета потока

Thread thread = new Thread(() -> {
    System.out.println("Running with priority " + Thread.currentThread().getPriority());
});

thread.setPriority(Thread.MAX_PRIORITY);  // 10
thread.start();

6. Практический пример с обработкой

public class ThreadManagementExample {
    public static void main(String[] args) throws InterruptedException {
        ExecutorService executor = Executors.newFixedThreadPool(2);
        
        for (int i = 1; i <= 4; i++) {
            final int taskId = i;
            executor.submit(() -> {
                System.out.println("Task " + taskId + " started");
                try {
                    Thread.sleep((long) (Math.random() * 3000));
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    System.out.println("Task " + taskId + " was interrupted");
                }
                System.out.println("Task " + taskId + " completed");
            });
        }
        
        executor.shutdown();
        executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
        System.out.println("All tasks completed");
    }
}

Сравнение подходов

СпособПреимуществаНедостаткиКогда использовать
Thread расширениеПростой стартНельзя наследовать другой классРедко (не рекомендуется)
RunnableМожно наследовать другой классНемного сложнееИногда, для простых случаев
ExecutorServiceУправление пулом, масштабируемостьНемного сложнееВсегда в production
Lambda (Java 8+)Компактно, современноТребует Java 8+В современных проектах

Ключевые выводы

  1. start() — создаёт новый поток
  2. run() — выполняет в текущем потоке (не используй!)
  3. ExecutorService — предпочтительный способ в production
  4. Graceful shutdown — всегда завершай пул потоков корректно
  5. Обработка InterruptedException — не игнорируй это исключение