Think about this scenario: you have a series of concurrent tasks, for example 10 threads each of them responsible download a web page with a URL. When finished you save them to somewhere like a database. But you don't want save them one by one, you want save them as one SQL statement, so you can not do database operation at the end of each task. You have to wait for all tasks completed then do the DB operation.

Put it simply, we need a callback function that will be triggered only when all tasks completed and accept all the results returned by a set of concurrent tasks. This post will show you how to do it with the future Reference Type in Clojure.

 
(defn download [url]
  (Thread/sleep (+ 0 (rand-int 1000)))
  (str "downloaded :"  url)
)
 
(defn callback [content-list]
  content-list
)
 
(defn download-with-callback [url-list callback]
  (callback (map #(deref %) (doall (map #(future (download %)) url-list))))
)
 
(download-with-callback ["urll" "url2" "url3"] callback)
 

In this code, we simulate download we page as a random sleep. Then we map a function on each url in url-list, this function will create a future object for downloading task. The doall is necessary, otherwise the future object is created one by one, the next object is created after the previous one finished. The doall make sure all future object are created at the same time, tasks will be executed in parallel.

Since each deref will be blocked until the thread complete, the callback only called after all future object has done.