Точные значения предсказать нельзя: incA++ и incB++ неатомарны, поэтому обновления теряются. CountDownLatch ждёт завершения и обеспечивает видимость, но не делает инкременты безопасными.
Одновременное увеличение двух счётчиков с помощью CountDownLatch
Точные значения предсказать нельзя: incA++ и incB++ неатомарны, поэтому обновления теряются. CountDownLatch ждёт завершения и обеспечивает видимость, но не делает инкременты безопасными.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
Программа создаёт 100 000 задач, которые выполняются одновременно в пуле из 100 потоков. Каждая задача увеличивает два общих счётчика — incA и incB. Для того чтобы дождаться завершения всех задач перед выводом результатов, используется объект CountDownLatch. Требуется предсказать, какие значения будут напечатаны в конце работы программы.
public class Increment {
private static int incA = 0;
private static int incB = 0;
public static void main(String[] args) throws InterruptedException {
int totalTasks = 100000;
CountDownLatch latch = new CountDownLatch(totalTasks);
ExecutorService executor = Executors.newFixedThreadPool(100);
for (int i = 0; i < totalTasks; i++) {
executor.submit(() -> {
incA++;
incB++;
latch.countDown();
});
}
latch.await();
System.out.println(incA);
System.out.println(incB);
System.exit(0);
}
}
Ответ
Точные значения предсказать нельзя: incA++ и incB++ неатомарны, поэтому обновления теряются. CountDownLatch ждёт завершения и обеспечивает видимость, но не делает инкременты безопасными.
Оба счётчика могут отличаться друг от друга и от 100000; равенство 100000 при удачном исполнении также не исключено. Используйте AtomicInteger.incrementAndGet либо LongAdder.increment и чтение после await. Если важно сохранять равенство пары во время работы, нужна общая блокировка для двух обновлений. CountDown размещают в finally, чтобы исключение задачи не оставило ожидание навсегда. Вместо System.exit предпочтительно корректно завершить executor через shutdown.