Clojure Threading with Future

Clojure concurrency is easy with future. Speed improvements in Clojure on modern computers come from multi-threading. Besides tapping into Java’s thread system, Clojure has it’s own easy-to-use thread system, and Clojure threads don’t get easier to use than with future.

In its simplest form, use def with a future and then then dereference the value obtained. When the future is no longer needed, make a call to shutdown-agents for the program to exit properly.

For example:

(ns clj-future.core)

(defn do-something
  "Doing something noticable."
  []
  
  "Life. Don't tell me about life.")

(defn -main
  "I don't do a whole lot."
  []
  
  ;; create a var named some-string
  ;; and make it reference our future
  (def some-string (future 
                     (do-something)))
  
  ;; dereference the future value
  ;; and print it
  (println @some-string)
  
  ;; remember to shut down agents
  ;; so the program exits normally
  (shutdown-agents))

The result of the above code is the Clojure program printing out, Life. Don’t tell me about life.

The program starts by a call to the -main function. Creating some-string with a call to def allows us access to the reference to our future‘s call to the do-something method.

If you’re coming from a Java world, you may be familiar with creating Threads, and then calling start() on those threads. Think of future as a Thread constructor and the start() method rolled into one quick call.

In Java, we’d have to call wait() or sleep() on the Thread to pause the program until our thread was done. Clojure cuts that extra step out. We use @ to dereference the variable some-string, and that pauses the thread requesting the value until some-string actually has a value. No worries about the program exiting before our thread is finished coming up with a value for some-string.

Simple.

One thread isn’t very exciting. We could do the same thing in the original thread. Now let’s show a similar program with three threads.

(ns clj-future.core)

(defn complex-calculation
  "Advanced math 101."
  [x]
  
  (println "calculating " x "++ ...")
  (Thread/sleep 5000)
  (inc x))

(defn -main
  "I don't do a whole lot."
  []
  
    (println "About to do some very "
             "complex math. Only trained "
             "professionals should attempt "
             "this.")
  
  ;; create a var named result1
  ;; and make it reference our future
  (def result1 (future 
                 (complex-calculation 1)))

  (Thread/sleep 1000)

  
  (def result2 (future 
                 (complex-calculation 10)))

  (Thread/sleep 1000)
  
  (def result3 (future 
                 (complex-calculation 100)))
  
  ;; dereference the future values
  ;; and print them
  (println "result 1 = " @result1)
  
  (println "result 2 = " @result2)
  
  (println "result 3 = " @result3)
  
  ;; remember to shut down agents
  ;; so the program exits normally
  (shutdown-agents))

We put some sleeps into this Clojure script just to simulate time-consuming calculations.

The printed result of running this code is:

About to do some very  complex math. Only trained  professionals should attempt  this.
calculating  1 ++ ...
calculating  10 ++ ...
calculating  100 ++ ...
result 1 =  2
result 2 =  11
result 3 =  101

Anyone doing real threading is going to be asking, What if I don’t want to wait for the thread to complete? That’s fine. You can use, a call to future-done to check if the value is ready for dereferencing.

For example:

(ns clj-future.core)

(defn do-something
  "Doing something noticable."
  []
  
  ;;add a little wait for our result
  (Thread/sleep 3000)
  
  ;; all done
  "Life. Don't tell me about life.")

(defn -main
  "I don't do a whole lot."
  []
  
  ;; create a var named some-string
  ;; and make it reference our future
  (def some-string (future 
                     (do-something)))
  
  (println "Ready yet? " 
           (future-done? some-string))
  (Thread/sleep 4000)
  (println "How about now? " 
           (future-done? some-string))
  
  ;; dereference the future value
  ;; and print it
  (println @some-string)
  
  ;; remember to shut down agents
  ;; so the program exits normally
  (shutdown-agents))

The resulting text is below. Notice that the first check is false, but the second check is true.

Ready yet?  false
How about now?  true
Life. Don't tell me about life.

One more note about shutdown-agents. Clojure’s future uses a thread pool in the background. Those threads stay in the pool, ready for fast action when needed. However, that also means that your Clojure programs using future never go away, because the thread pool never goes away. That is why we call shutdown-agents when future is done. Making the call to shutdown-agents makes the thread pool go away.

You don’t need to worry about calling shutdown-agents before the future is finished doing its thing, however. Because the call to shutdown-agents, just shuts down the thread pool. Threads still running don’t disappear until they terminate normally.