### Atoms
Atoms 提供了一种比使用Refs&STM更简单的更新当个值的方法。它不受事务的影响
有三个函数可以修改一个Atom的值: `reset!` , `compare-and-set!` 和 `swap!` .
`reset!` 函数接受两个参数:要设值的Atom以及新值。它设置新的值,而不管你旧的值是什么。看例子:
```
(def my-atom (atom 1))
(reset! my-atom 2)
(println @my-atom) ; -> 2
```
`compare-and-set!` 函数接受三个参数:要被修改的Atom, 上次读取时候的值,新的值。 这个函数在设置新值之前会去读Atom现在的值。如果与上次读的时候的值相等, 那么设置新值并返回true, 否则不设置新值, 返回false。看例子:
```
(def my-atom (atom 1))
(defn update-atom []
(let [curr-val @my-atom]
(println "update-atom: curr-val =" curr-val) ; -> 1
(Thread/sleep 50) ; give reset! time to run
(println
(compare-and-set! my-atom curr-val (inc curr-val))))) ; -> false
(let [thread (Thread. #(update-atom))]
(.start thread)
(Thread/sleep 25) ; give thread time to call update-atom
(reset! my-atom 3) ; happens after update-atom binds curr-val
(.join thread)) ; wait for thread to finish
(println @my-atom) ; -> 3
```
为什么最后的结果是 3呢? `update-atom` 被放在一个单独的线程里面,在 `reset!` 函数调用之前执行。所以它获取了atom的初始值1(存到变量curr-val里面去了), 然后它sleep了以让 `reset!` 函数有执行是时间。在那之后,atom的值就变成3了。当 `update-atom` 函数调用 `compare-and-set!` 来给这个值加一的时候, 它发现atom的值已经不是它上次读取的那个值了(1), 所以更新失败, atom的值还是3。
`swap!` 函数接受一个要修改的 Atom, 一个计算Atom新值的函数以及一些额外的参数(如果需要的话)。这个计算Atom新的值的函数会以这个Atom以及一些额外的参数做为输入。swap!函数实际上是对compare-and-set!函数的一个封装,但是有一个显著的不同。 它首先把Atom的当前值存入一个变量,然后调用计算新值的函数来计算新值, 然后再调用compare-and-set!函数来赋值。如果赋值成功的话,那就结束了。如果赋值不成功的话, 那么它会重复这个过程,一直到赋值成功为止。这就是它们的区别:所以上面的代码可以用swap!改写成这样:
```
(def my-atom (atom 1))
(defn update-atom [curr-val]
(println "update-atom: curr-val =" curr-val)
(Thread/sleep 50) ; give reset! time to run
(inc curr-val))
(let [thread (Thread. #(swap! my-atom update-atom))]
(.start thread)
(Thread/sleep 25) ; give swap! time to call update-atom
(reset! my-atom 3)
(.join thread)) ; wait for thread to finish
(println @my-atom) ; -> 4
```
为什么输出变成4了呢?因为swap!会不停的去给curr-val加一直到成功为止。