Thread.join
worker.join() заставляет текущий поток ждать завершения worker.
Thread loader = new Thread(() -> loadCache(), "cache-loader");
loader.start();
loader.join();
useCache();У join() есть не только координация, но и гарантия памяти: все действия завершившегося потока happens-before успешного возврата из join() в ожидающем потоке. Поэтому useCache() увидит записанные loader данные, если объект опубликован корректно.
Тайм-аут
loader.join(500);
if (loader.isAlive()) {
loader.interrupt();
}Возврат из timed join() не означает завершение: тайм-аут нужно отличать через isAlive() или более подходящую абстракцию результата.
join() бросает InterruptedException, если прервали ожидающий поток. Это сигнал отмены его ожидания, а не автоматическая остановка loader.
try {
loader.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return;
}В прикладном коде чаще подходят Future.get(), CompletableFuture или структурированный жизненный цикл executor: они связывают ожидание с результатом и ошибкой.
На собеседовании
- Какой поток блокируется при
a.join()? Тот, который вызвал метод, а неa. - Что гарантирует обычный возврат из
join()? Целевой поток завершен, а его действия видимы ожидающему. - Что гарантирует timed
join()? Только то, что ожидание закончилось; поток мог остаться жив. - Освобождает ли
join()мониторы, ранее захваченные вызывающим кодом? Нет; ждать под своей блокировкой опасно.