Когда исключение выдается в одном потоке, оно не распространяется на другие потоки, если вы не сделаете что-то для этого (например, используя Future). Здесь поток вызывает исключение и умирает, но остальная часть программы не затрагивается.
Исполнитель создает замену для потерянного потока, см. API-документ:
Создает Исполнителя, который использует один рабочий поток, работающий из неограниченной очереди, и использует предоставленную ThreadFactory для создания нового потока, когда это необходимо. В отличие от эквивалентного newFixedThreadPool (1, threadFactory) в противном случае возвращаемый исполнитель гарантированно не реконфигурируется для использования дополнительных потоков.
Мне кажется хорошей идеей, чтобы задачи обрабатывали исключения, которые они вызывают. В противном случае поток умирает, и пул должен начать новый, чтобы заменить его. Это в основном то, что говорится в статье в комментариях.