首页 文章

未来总是会创建一个新线程吗?

提问于
浏览
4

假设我这样做:

(future
  (do-the-thing))

我保证,无论 (do-the-thing) 做什么,

  • 将创建一个全新的线程,而不是从池中获取一个或类似的东西?

  • 除了 (do-the-thing) 之外什么都不会在新线程上运行?

  • 一旦 (do-the-thing) 在该新线程上执行,该线程将终止?

如果不是,在什么情况下这些假设是假的?

1 回答

  • 4

    简短的回答是 No

    来自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));
    

    您可以看到 soloExecutorExecutors.newCachedThreadPool() 创建

    来自document of Executors.newCachedThreadPool

    创建一个根据需要创建新线程的线程池,但在它们可用时将重用先前构造的线程 . 这些池通常会提高执行许多短期异步任务的程序的性能 . 如果可用,执行调用将重用先前构造的线程 . 如果没有可用的现有线程,则将创建一个新线程并将其添加到池中 . 未使用60秒的线程将终止并从缓存中删除 . 因此,长时间闲置的池不会消耗任何资源 . 请注意,可以使用ThreadPoolExecutor构造函数创建具有相似属性但不同详细信息的池(例如,超时参数) .

    所以答案是 (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
    

    因此,您可以确认先前的线程已终止并且已创建新线程 .

相关问题