Для чего нужен метод join() у класса Thread в Java?

Ответ

Метод Thread.join() заставляет текущий поток ожидать завершения потока, на котором он вызван. Вызывающий поток блокируется до тех пор, пока целевой поток не завершит выполнение.

Базовый пример:

Thread worker = new Thread(() -> {
    System.out.println("Поток начал работу");
    try { Thread.sleep(2000); } catch (InterruptedException e) {}
    System.out.println("Поток завершил работу");
});

worker.start();
System.out.println("Основной поток запустил worker и ждёт...");
worker.join(); // Основной поток ждёт здесь завершения потока 'worker'
System.out.println("Основной поток продолжает работу после join.");

Варианты метода:

  • join() – ждёт бесконечно.
  • join(long millis) – ждёт не более указанного времени в миллисекундах.
  • join(long millis, int nanos) – с точностью до наносекунд.

Особенности:

  • Если целевой поток уже завершён, join() возвращается немедленно.
  • Метод может выбросить InterruptedException, если ожидающий поток будет прерван.
  • Используется для синхронизации порядка выполнения потоков.

Ответ 18+ 🔞

А, ну ты глянь, какой у нас тут придурок Thread.join() объявился! Сидит, понимаешь, как будто в дверном проёме, и не пускает дальше, пока его братан-поток не отмучается. Представь: ты запустил какую-то хуйню в отдельном потоке, а самому надо, чтобы она точно доделалась, прежде чем ты свою продолжишь. Вот тут он и пригодится, этот затычка.

Смотри, как это выглядит в деле:

Thread worker = new Thread(() -> {
    System.out.println("Поток начал работу");
    try { Thread.sleep(2000); } catch (InterruptedException e) {}
    System.out.println("Поток завершил работу");
});

worker.start();
System.out.println("Основной поток запустил worker и ждёт...");
worker.join(); // Вот эта строчка! Основной поток тут встал колом и ждёт, пока worker не сдохнет.
System.out.println("Основной поток продолжает работу после join.");

Выполнишь — и увидишь эту подлую синхронизацию: основной поток выведет своё «ждёт...» и, блядь, замрёт на две секунды, как вкопанный. Только когда worker отстреляется и напишет «завершил работу», основной поток охуеет от скуки и потащится дальше.

А вариантов у этого гвоздя в жопе аж три:

  • join() – будет ждать до победного конца, хоть до второго пришествия. Если поток уже кончился — ну, красава, проходи, не задерживай.
  • join(long millis) – тут уже с таймером. «Я, сука, подожду ровно столько миллисекунд, а там — похуй, завершился он или нет, мне дальше надо».
  • join(long millis, int nanos) – для совсем ебнутых перфекционистов, которым и наносекунды покоя не дают.

Важные нюансы, чтобы не обосраться:

  • Если поток, на котором вызываешь join(), уже труп (завершился), то метод сразу тебя отпустит, не задерживая.
  • Может выкинуть InterruptedException — это если тебя, пока ты терпеливо ждёшь, вдруг прервут по-хамски. Придёшь в себя — обрабатывай.
  • В общем, инструмент для тех случаев, когда нужно выстроить потоки в очередь, чтобы они не неслись, как тараканы, кто куда попало. Синхронизация, ёпта, мать её.