Gymterview
junior

Даны 3 потока Т1, Т2 и Т3. Как реализовать выполнение в последовательности Т1, Т2, Т3?

Существует несколько способов обеспечить последовательное выполнение потоков.

Способ 1: Thread.join() (самый простой)

Метод join() блокирует вызывающий поток до завершения целевого потока.

Пример
Thread t1 = new Thread(() -> System.out.println("T1"));
Thread t2 = new Thread(() -> System.out.println("T2"));
Thread t3 = new Thread(() -> System.out.println("T3"));

t1.start();
t1.join(); // Ждём завершения T1

t2.start();
t2.join(); // Ждём завершения T2

t3.start();
t3.join(); // Ждём завершения T3

Способ 2: join() внутри потоков

Каждый поток вызывает join() на предыдущем:

Пример
Thread t1 = new Thread(() -> System.out.println("T1"));

Thread t2 = new Thread(() -> {
    try { t1.join(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
    System.out.println("T2");
});

Thread t3 = new Thread(() -> {
    try { t2.join(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
    System.out.println("T3");
});

// Порядок запуска не важен!
t3.start();
t2.start();
t1.start();

Способ 3: CountDownLatch

Пример
CountDownLatch latch1 = new CountDownLatch(1);
CountDownLatch latch2 = new CountDownLatch(1);

Thread t1 = new Thread(() -> {
    System.out.println("T1");
    latch1.countDown();
});

Thread t2 = new Thread(() -> {
    try { latch1.await(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
    System.out.println("T2");
    latch2.countDown();
});

Thread t3 = new Thread(() -> {
    try { latch2.await(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
    System.out.println("T3");
});

t3.start(); t2.start(); t1.start();

Способ 4: ExecutorService с одним потоком

Пример
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(() -> System.out.println("T1"));
executor.submit(() -> System.out.println("T2"));
executor.submit(() -> System.out.println("T3"));
executor.shutdown();

newSingleThreadExecutor() гарантирует выполнение задач строго последовательно в порядке их подачи.

На собеседовании наиболее ожидаемый ответ — через join(). Но если упомянете CountDownLatch или SingleThreadExecutor, это покажет знание инструментов java.util.concurrent.