我们使用 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,以便实现更高的读取并发性
* 其他方案:*
* 对于 _meta 使用 volatile,对于 alter/reset 使用 synchronized。允许在 volatile 下读取 _meta - 这是否足够安全?
* 从 ReentrantReadWriteLock 继承 AReference,而不是持有它 - 这很奇怪,但可能对内存/构建带来不同的(可能是更好的)影响。