Executors.newSingleThreadScheduledExecutor() を使用して Clojure 関数をスケジュールしようとしています。厄介なのは、結果の ScheduledFutureTask で .get() を呼び出すと、関数の結果ではなく nil が返されることです。
私はヒッキー氏の先物の実装をモデルとして採用しています。
(ns my.ns
(:import (java.util.concurrent Executors ThreadFactory TimeUnit)))
(def ^:private thread-pool-scheduler (atom nil))
(def ^:private thread-pool-counter (agent 0))
(defn- get-and-increment-thread-id []
(-> thread-pool-counter (send inc) deref))
(def ^:private thread-factory
(reify ThreadFactory
(newThread [this f]
(let [thread (Thread. f)]
(.setName thread (format "clojure-scheduled-future-thread-pool-%d"
(get-and-increment-thread-id)))
thread))))
(defn scheduled-future-call [^Callable f ^long delay ^TimeUnit unit]
(.schedule (scheduled-futures-executor) (bound-fn* f) delay unit))
(defn start-scheduled-futures-executor! []
(reset! thread-pool-scheduler
(Executors/newSingleThreadScheduledExecutor thread-factory)))
(defn scheduled-futures-executor []
(or @thread-pool-scheduler
(start-scheduled-futures-executor!)))
すべてが機能し、適切な場合に副作用が発生します (例: #(println "ok") のスケジューリング)。ただし、結果の ScheduledFutureTask の get() メソッドを呼び出すと、常に nil が返されます (例: #(+ 5 5) のスケジューリング)。
Callable を明示的に拡張しようとしましたが、bound-fn* を省略しようとしましたが、結果は同じです。
(defprotocol ISchedule
(schedule [this delay time-unit]))
(extend Callable
ISchedule
{:schedule (fn [this delay time-unit]
(.schedule (scheduled-futures-executor) this delay time-unit))})
私の直感では、ScheduledExecutorService は schedule(Runnable, long, TimeUnit) よりも schedule(Callable, long, TimeUnit) を選択していますが、ヒントを入力して修正しないでください。
助けやヒントをありがとう!