Happens-before
Happens-before — отношение порядка в Java Memory Model. Если действие A happens-before B, эффекты A должны быть видимы B, а допустимое исполнение согласуется с этим порядком. Это логическая гарантия, а не обязательно разница во времени на физических часах.
Основные правила
| A | Happens-before B |
|---|---|
| действие в потоке | следующее действие этого же потока |
выход из synchronized | следующий вход в тот же monitor |
запись в volatile | последующее чтение этого записанного значения |
thread.start() | действия запущенного потока |
| действия потока | успешный возврат другого потока из join() |
| инициализация класса | первое активное использование класса |
Отношение транзитивно: если A предшествует B, а B предшествует C, то A предшествует C.
int payload = 0;
Thread producer = new Thread(() -> payload = 42);
producer.start();
producer.join();
System.out.println(payload); // join гарантирует видимость 42Executor и Future
Для executor действует точное правило: действия потока до передачи Runnable
или Callable happens-before действия задачи. Действия задачи, в свою очередь,
happen-before получением результата через Future.get().
List<String> input = List.of("a", "bb");
Future<Integer> future = pool.submit(
() -> input.stream().mapToInt(String::length).sum());
int total = future.get(); // видит результат задачиСам факт, что две независимые задачи выполняются одним executor, не создаёт
между ними happens-before. Нужна явная граница: Future.get, lock, volatile,
latch, очередь или другой синхронизатор.
Что правило не гарантирует
- A и B не обязаны выполняться на разных ядрах или в разные моменты часов.
- Happens-before не означает атомарность составной операции.
sleep()иyield()не публикуют состояние.- «До по исходному коду» между разными потоками недостаточно.
Вопросы для собеседования
- Что гарантирует happens-before? Видимость эффектов и допустимый порядок.
- Создаёт ли
startсвязь? Да, действия доstartвидимы новому потоку. - Что гарантирует
join? Действия завершившегося потока видимы после join. - Есть ли связь между двумя задачами пула автоматически? Нет.
- Что даёт
Future.get? Видимость действий завершённой задачи и её результат. - Создаёт ли
Thread.sleephappens-before? Нет. - Почему важна транзитивность? Она переносит видимость через цепочку синхронизационных границ.