clj -m cljs.main -re nashorn
(def thread (.type js/Java "java.lang.Thread"))
(let [global-atom-lock
(let [ctor (.type js/Java "java.util.concurrent.locks.ReentrantLock")]
(new ctor))]
(defn swap!
[a f & args]
(loop [old-val @a]
(let [new-val (apply f old-val args)]
(.lock global-atom-lock)
(if (= @a old-val)
(do
(cljs.core/reset! a new-val)
(.unlock global-atom-lock)
new-val)
(do
(.unlock global-atom-lock)
(recur @a))))))
(defn reset! [a new-value]
(.lock global-atom-lock)
(cljs.core/reset! a new-value)
(.unlock global-atom-lock)
new-value))
(def initial-value {:v 0
:a {:v 0
:b {:v 0
:c {:v 0
:d {:v 0
:e {:v 0
:f {:v 0}}}}}}})
(def x (atom initial-value))
(defn worker []
(swap! x update-in (concat (take (rand-int 7) [:a :b :c :d :e :f]) [:v]) inc)
(.sleep thread 10)
(recur))
(dotimes [_ 100]
(.start (new thread worker)))
Then try evaluating @x
to see if it rips itself apart. You should see values like
{:v 282904, :a {:v 280910, :b {:v 282212, :c {:v 281561, :d {:v 282548, :e {:v 282555, :f {:v 282178}}}}}}}
You can also do this:
(swap! x update-in (concat (take (rand-int 7) [:a :b :c :d :e :f]) [:v]) inc)
You can also
(reset! x initial-value)