Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does future always create a new thread?

Let's say I do this:

(future
  (do-the-thing))

Am I guaranteed that, regardless of what (do-the-thing) does,

  • an entirely new thread will be created, rather than getting one from a pool or anything like that?
  • nothing other than (do-the-thing) will ever run on that new thread?
  • once (do-the-thing) executes on that new thread, the thread will terminate?

If not, under what circumstances would these assumptions be false?

like image 845
Sam Estep Avatar asked Feb 26 '16 01:02

Sam Estep


People also ask

What does Future get do?

A Future interface provides methods to check if the computation is complete, to wait for its completion and to retrieve the results of the computation. The result is retrieved using Future's get() method when the computation has completed, and it blocks until it is completed.

What is Future multithreading?

Think of a Future as an object that holds the result – it may not hold it right now, but it will do so in the future (once the Callable returns). Thus, a Future is basically one way the main thread can keep track of the progress and result from other threads.

What is Future in Java concurrency?

A Future represents the result of an asynchronous computation. Methods are provided to check if the computation is complete, to wait for its completion, and to retrieve the result of the computation.

How do I start a new thread?

Starting a Thread With a Runnable Thread thread = new Thread(runnable); thread. start(); When the thread is started it will call the run() method of the MyRunnable instance instead of executing it's own run() method.


1 Answers

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.

like image 181
ymonad Avatar answered Sep 17 '22 18:09

ymonad