Исполнитель - это концептуально очередь задач + рабочий пул. Ваше объяснение того, что здесь произойдет, в основном верно. Когда вы отправляете задачу исполнителю, работа ставится в очередь до тех пор, пока поток не сможет выполнить задачу. Когда она выполняет задачу, эта задача владеет потоком, и спящий режим заблокирует выполнение других задач в этом рабочем потоке.
В зависимости от того, что вы делаете, это может быть нормально (хотя это необычно и, вероятно, плохо спать внутри задачи). Чаще всего блокируют поток как побочный эффект ожидания ввода-вывода (например, блокируется при вызове сокета или db).
Обычно, если вы выполняете периодическую работу, лучше обрабатывать ее вне пула и запускать задачи, когда они должны быть выполнены, или, что еще лучше, использовать ScheduledExecutorService вместо из Executors / newScheduledThreadPool.
Другим основным механизмом в Java для выполнения задач, основанных на времени, является java.util.Timer , который немного проще в использовании, но не так надежен, как ScheduledExecutorService.
Другая альтернатива из Clojure - это явное помещение рабочего в фоновый поток, управляемый Clojure, а не вами:
(defn do-task []
(println (java.util.Date.) "doing task"))
(defn worker [f n wait]
(doseq [task (repeat n f)]
(f)
(Thread/sleep wait)))
;; use future to execute worker in a background thread managed by Clojure
(future (worker do-task 10 1000))
;; the call to future returns immediately but in the background console
;; you will see the tasks being run.