Java. Менторинг за чашкой кода

@channel_java_cup_code
ExecutorService: как запускать потоки и не уронить прод В прошлый раз мы выбрали правильные коллекции. Но сама по себе потокобезопасная структура мертва, пока её не начнут дергать потоки. Типичная ошибка — породить тысячу тредов через `new Thread()`: // ПЛОХОЙ КОД for (int i = 0; i < 1000; i++) { new Thread(() -> callApi(i)).start(); } ОС просто убьет такой процесс из-за нехватки ресурсов или задушит переключениями контекста. Как делаем мы Используем пул потоков (ExecutorService). Мы описываем задачу, а пул сам решает, какой свободный воркер её заберет. Базовый шаблон работы выглядит так: / / Пул размером с количество ядер CPU ExecutorService executor = Executors.newFixedThreadPool( Runtime.getRuntime().availableProcessors() ); // Запускаем задачи for (int i = 0; i < 10_000; i++) { int id = i; // submit возвращает Future — ручку для отслеживания результата executor.submit(() -> processTask(id)); } // Мягко останавливаем прием новых задач executor.shutdown(); try { // Ждем завершения запущенных (максимум 2 минуты) if (!executor.awaitTermination(2, TimeUnit.MINUTES)) { System.err.println("Принудительная отмена"); executor.shutdownNow(); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); // Восстанавливаем флаг прерывания executor.shutdownNow(); } Три правила, чтобы спать спокойно: * Исключения. Ошибки внутри обычного Runnable проглатываются. Если хотим их видеть — используем Callable<V> и вызываем future.get(). Там любое исключение вылетит наружу в виде ExecutionException. * Размер пула. Для тяжелых вычислений (CPU-bound) ставим столько нитей, сколько физических ядер. Для ожидания сети или диска (IO-bound) — больше, например (ядра * 2), чтобы пока одни спят, другие работали. * Shutdown vs ShutdownNow. Первый мягко закрывает входную дверь. Второй пытается прервать уже работающие нити через thread.interrupt(). Наш код обязан уметь обрабатывать InterruptedException и быстро завершаться. Забудьте про ручной new Thread(). Любой фоновый чих должен идти через ExecutorService. Это дает контроль над памятью и позволяет приложению нормально закрыться.
Если у вас установлено приложение,
вы можете сразу перейти в канал