Reputation: 13324
Let's say I do this:
(future
(do-the-thing))
Am I guaranteed that, regardless of what (do-the-thing)
does,
(do-the-thing)
will ever run on that new thread?(do-the-thing)
executes on that new thread, the thread will terminate?If not, under what circumstances would these assumptions be false?
Upvotes: 9
Views: 2736
Reputation: 12090
Short answer is No
From clojure's core.clj:
(defmacro future
...
[& body] `(future-call (^{:once true} fn* [] ~@body)))
...
(defn future-call
...
[f]
(let [f (binding-conveyor-fn f)
fut (.submit clojure.lang.Agent/soloExecutor ^Callable f)]
...
So the executor of the future is clojure.lang.Agent/soloExecutor
.
From Agent.java:
volatile public static ExecutorService soloExecutor = Executors.newCachedThreadPool(
createThreadFactory("clojure-agent-send-off-pool-%d", sendOffThreadPoolCounter));
You can see that soloExecutor
is created by Executors.newCachedThreadPool()
From document of Executors.newCachedThreadPool:
Creates a thread pool that creates new threads as needed, but will reuse previously constructed threads when they are available. These pools will typically improve the performance of programs that execute many short-lived asynchronous tasks. Calls to execute will reuse previously constructed threads if available. If no existing thread is available, a new thread will be created and added to the pool. Threads that have not been used for sixty seconds are terminated and removed from the cache. Thus, a pool that remains idle for long enough will not consume any resources. Note that pools with similar properties but different details (for example, timeout parameters) may be created using ThreadPoolExecutor constructors.
So the answer is some other job of (do-the-thing)
may be executed in same thread, and the thread will be terminated after 60 seconds if there's no more job.
You can confirm the behavior of Executors.newCachedThreadPool
in following code:
(doseq [i (for [x (range 10)] (future (Thread/sleep 1000) (.getId (Thread/currentThread))))] (print @i) (print " "))
Executing this code in clojure console, you get:
50 49 48 47 46 45 44 43 42 41 nil
for first time. And execute it again after 5 seconds, you get:
50 49 43 41 45 42 46 47 48 44 nil
Therefore you can confirm that the thread is reused.
If you execute same code after 60 seconds, you get:
60 59 58 57 56 55 54 53 52 51 nil
So you can confirm that previous threads were terminated and new threads were created.
Upvotes: 9