Во-первых, причина, по которой вы видите странные результаты, заключается в том, что вы разыменовываете future
, а не атом, содержащий число. Будущее вернет результат swap!
при разыменовании.
Во-вторых, вы можете использовать locking
(в основном Java synchronized
), чтобы разрешить увеличение и печать только одного потока за один раз:
(def n-atom (atom 0))
(defn action []
; Arbitrarily chose the atom to lock on.
; It would probably be better to create a private object that can't be otherwise used.
(locking n-atom
(println
(swap! n-atom inc))))
(defn go []
; Have each thread do action twice for a total of four times
(future (doall (repeatedly 2 action)))
(future (doall (repeatedly 2 action))))
(go)
1
2
3
4
Замечу, однако, что future
здесь действительно не следует использовать. future
для случаев, когда вы хотите вычислить результат асинхронно. Он проглатывает ошибки до тех пор, пока не разыменуется, поэтому, если вы никогда не @
, вы никогда не увидите исключений, которые появляются внутри future
. Было бы лучше использовать пул потоков или, с помощью макроса, для простоты использования, запустить два потока самостоятельно:
(defmacro thread
"Starts the body in a new thread."
[& body]
`(doto (Thread. ^Runnable (fn [] ~@body))
(.start)))
(defn go []
(thread (doall (repeatedly 2 action)))
(thread (doall (repeatedly 2 action))))