未来是否总是创建一个新线程?
Does future always create a new thread?
假设我这样做:
(future
(do-the-thing))
我能保证,无论 (do-the-thing)
做什么,
- 将创建一个全新的线程,而不是从池或类似的东西中获取线程?
- 除了
(do-the-thing)
之外,其他任何东西都不会 运行 在那个新线程上?
- 一旦
(do-the-thing)
在该新线程上执行,该线程将终止?
如果不是,在什么情况下这些假设是错误的?
简短的回答是否
来自 clojure 的 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)]
...
所以未来的执行人是clojure.lang.Agent/soloExecutor
.
来自 Agent.java:
volatile public static ExecutorService soloExecutor = Executors.newCachedThreadPool(
createThreadFactory("clojure-agent-send-off-pool-%d", sendOffThreadPoolCounter));
可以看到soloExecutor
是由Executors.newCachedThreadPool()
创建的
来自 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.
所以答案是 (do-the-thing)
的一些其他作业可能在同一个线程中执行,如果没有更多作业,线程将在 60 秒后终止。
您可以在以下代码中确认 Executors.newCachedThreadPool
的行为:
(doseq [i (for [x (range 10)] (future (Thread/sleep 1000) (.getId (Thread/currentThread))))] (print @i) (print " "))
在 clojure 控制台中执行此代码,您将获得:
50 49 48 47 46 45 44 43 42 41 nil
第一次。 5秒后再次执行,得到:
50 49 43 41 45 42 46 47 48 44 nil
因此可以确认线程被重用了。
如果您在 60 秒后执行相同的代码,您将得到:
60 59 58 57 56 55 54 53 52 51 nil
因此您可以确认之前的线程已终止并创建了新线程。
假设我这样做:
(future
(do-the-thing))
我能保证,无论 (do-the-thing)
做什么,
- 将创建一个全新的线程,而不是从池或类似的东西中获取线程?
- 除了
(do-the-thing)
之外,其他任何东西都不会 运行 在那个新线程上? - 一旦
(do-the-thing)
在该新线程上执行,该线程将终止?
如果不是,在什么情况下这些假设是错误的?
简短的回答是否
来自 clojure 的 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)]
...
所以未来的执行人是clojure.lang.Agent/soloExecutor
.
来自 Agent.java:
volatile public static ExecutorService soloExecutor = Executors.newCachedThreadPool(
createThreadFactory("clojure-agent-send-off-pool-%d", sendOffThreadPoolCounter));
可以看到soloExecutor
是由Executors.newCachedThreadPool()
来自 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.
所以答案是 (do-the-thing)
的一些其他作业可能在同一个线程中执行,如果没有更多作业,线程将在 60 秒后终止。
您可以在以下代码中确认 Executors.newCachedThreadPool
的行为:
(doseq [i (for [x (range 10)] (future (Thread/sleep 1000) (.getId (Thread/currentThread))))] (print @i) (print " "))
在 clojure 控制台中执行此代码,您将获得:
50 49 48 47 46 45 44 43 42 41 nil
第一次。 5秒后再次执行,得到:
50 49 43 41 45 42 46 47 48 44 nil
因此可以确认线程被重用了。
如果您在 60 秒后执行相同的代码,您将得到:
60 59 58 57 56 55 54 53 52 51 nil
因此您可以确认之前的线程已终止并创建了新线程。