Здесь:
public static ExecutorService executor = Executors.newFixedThreadPool(4);
Вы создаете этот пул потоков один раз. Позже вы звоните
executor.shutdownNow();
Другими словами: вы заводите свою машину, и в какой-то момент вы останавливаете машину, выходите из машины и поджигаете ее. Тогда вы спрашиваете себя: «Хорошо, как я могу использовать эту машину, чтобы ехать домой?». Ну, ты не можешь. Вы просто подожгли его.
То же самое и здесь: когда вы выключаете службу, она исчезает .
Короче говоря, простое (не обязательно идеальное) решение было бы сделать:
public static ExecutorService executor = null;
и позже:
if (executor == null)
executor = Executors.newFixedThreadPool(4);
и
executor.shutdownNow();
executor = null;
Другими словами: вы едете на своей машине, поджигаете ее, а затем покупаете новую, чтобы совершить другую, прежде чем поджечь ее.
Конечно, такой подход установки нуля и проверки на это может привести к различным проблемам. Было бы немного лучше сделать:
executor.shutdownNow();
executor = Executors.newFixedThreadPool(4);
Значение: вместо того, чтобы оставлять исполнителя равным нулю, вы просто создаете новый экземпляр, как только «последнему» было приказано завершить работу. Таким образом, теоретически, всякий раз, когда исполнитель привыкает выполнять задачи ИЛИ отключается, вы говорите с «действительным» в данный момент экземпляром.