第4章:Clojure的STM(软件事务内存)
一、导读
1.1 本章学习目标
第4章深入讲解 Clojure 的 STM(Software Transactional Memory)——一种用数据库事务的思想来解决并发问题的模型。
本章的核心学习目标包括:
- 理解 STM 的工作原理
- 掌握 MVCC(多版本并发控制)
- 理解 STM 的隔离性保证
- 学会使用 STM 解决复杂的并发问题
1.2 为什么本章如此重要
STM 将数据库事务的概念引入内存操作——原子性、一致性、隔离性。它让并发编程变得像写数据库事务一样简单。理解 STM,能帮你理解分布式系统中的一致性保证。
1.3 核心问题引导
STM 和数据库事务有什么相似之处?
MVCC 是如何实现无锁并发的?
STM 的性能开销有多大?
STM 适合什么类型的问题?
二、核心概念详解
2.1 STM 基础
clojure
;; Ref 是 STM 的核心
(def balance (ref 100))
;; dosync 开启事务
(dosync
(alter balance - 50))
;; 事务保证:
;; 1. 原子性:要么全部成功,要么全部失败
;; 2. 一致性:事务结束时状态一致
;; 3. 隔离性:并发事务互不干扰2.2 MVCC
clojure
;; STM 使用 MVCC:每个事务看到一致的快照
;; 如果冲突,事务自动重试
(def x (ref 0))
(def y (ref 0))
;; 事务1:读取 x,修改 y
(future
(dosync
(let [x-val @x]
(Thread/sleep 100) ;; 模拟长时间操作
(alter y + x-val))))
;; 事务2:修改 x
(future
(dosync
(alter x inc)))
;; STM 自动处理冲突:如果事务1提交时发现 x 已被修改,会自动重试2.3 validate 函数
clojure
;; 为 Ref 添加验证
(def account (ref 0 :validator #(>= % 0)))
;; 验证失败会抛出异常
(dosync
(alter account - 100)) ;; 抛出 IllegalStateException三、实战案例
3.1 案例一:并发计数器
clojure
(def counters (ref (zipmap (range 10) (repeat 0))))
(defn increment [key]
(dosync
(alter counters update key inc)))
;; 并发递增
(dotimes [i 1000]
(future (increment (rand-int 10))))
(Thread/sleep 2000)
(println @counters)四、本章小结
STM:用事务的方式管理内存操作。
MVCC:多版本并发控制,避免锁的使用。
自动重试:冲突时事务自动重试。
验证器:为 Ref 添加约束条件。
五、思考与练习
STM 的自动重试在什么情况下可能导致问题?
STM 和锁并发相比,性能如何?
设计一个使用 STM 的并发数据结构。