我们使用 Clojure 打“规则引擎”。每个函数代表一条规则,元数据描述规则并提供规则本身的某些静态配置。该系统是不可变的和并发的。
如果有两个或更多线程并发调用同一个 Var,由于 AReference#meta() 是同步的,它们将最终互相阻塞(请参见附图,红色点)。
(defn
^{:rule {:remote-address "127.0.0.1"}}
example
[request]
(let [rule (:rule (meta #'example))]
(= (:remote-address rule) (:remote-address request))))
*方法:* 用 rwlock 替换同步块以提高读并发性。这种方法消除了元数据读冲突(请参见评论中的实际例子)。但是,它也有一些缺点:*
* 每个 AReference 都需要额外的字段(所有命名空间、vars、atoms、refs 和 agents)*
* 将锁的构建加入到 AReference 的构建中(影响性能和启动时间)*
*补丁:* clj-1888-2.patch 用 rwlock 替换 synchronized 以提高读并发性
*替代方案:**
* 使用 volatile 来处理 _meta,并使用 synchronized 处理 alter/reset。允许在 volatile 之下读取 _meta——这是否足够安全?*
* 从 ReentrantReadWriteLock 扩展 AReference 而不是保留一个——这听起来有些奇怪,但可能对内存/构建有不同(可能更好的)影响。