Clojure STM(dosync)x Java同步块

CHA*_*APa 11 java concurrency synchronization clojure stm

Clojure STM(dosync)方法和Java同步Block有什么区别?

我正在阅读"睡觉的理发师"问题下面的代码.(http://www.bestinclass.dk/index.clj/2009/09/scala-vs-clojure-round-2-concurrency.html)

(defn the-shop [a]  
  (print "[k] entering shop" a)  
  (dosync     
    (if (< (count @queue) seats)  
      (alter queue conj a)  
      (print "[s] turning away customer" a))))
Run Code Online (Sandbox Code Playgroud)

为了避免竞争条件,dosync使用,所以我问自己"Java同步块有什么区别(STM)"?它会阻止这个关键代码吗?

提前致谢 !丹塔斯

Mic*_*zyk 20

dosyncsynchronized允许访问完全不同的并发抽象.

synchronized是一种获取和释放锁的方法.当一个线程进入一个synchronized块时,它会尝试获取适当的锁; 如果锁当前由另一个线程持有,则当前线程会阻塞并等待它被释放.这导致某些问题,例如死锁的风险.线程离开synchronized块时释放锁定.

dosync标记要在事务中运行的代码块.Clojure中的事务是一种协调对Refs(使用该ref函数创建的对象)的更改的方法; 如果你需要一些代码来在Clojure中对一些可变状态进行一致的视图 - 并且可能会改变它们 - 你将它们放在Refs中并在事务中执行你的代码.

事务具有有趣的属性,如果由于某种原因它不能提交它将重新启动,直到某个最大重试次数(当前硬编码为10000).交易无法提交的可能原因之一是无法获得一致的世界观(实际上,相关的参考资料 - 有一个"自适应历史"设施,这使得这个问题不像它在乍一看); 其他交易同时发生的变化; 等等

事务不会有死锁的风险(除非程序员通过Java互操作引入与STM系统无关的死锁); 另一方面,活锁是一种可能性,尽管它不太可能.一般来说,很多 - 虽然不是全部! - 与数据库事务相关联的直觉程序员在STM系统的上下文中是有效的,包括Clojure的系统.

STM是一个很大的话题; 学习Clojure STM的一个很好的资源是Mark Volkmann的Software Transactional Memory文章.它在最后部分讨论Clojure的STM时深入探讨,但开始时可以作为很好的介绍性阅读.

至于你引用的片段,实际上并不是你通常想要在生产代码中模拟的东西,因为dosync块几乎总是没有副作用; 在print这里可以为演示STM的内部工作是有用的,但是如果你想要一个交易造成实际的代码的副作用,你应该有它产生一个Clojure的代理为目的(这只有在交易执行其任务成功提交).

  • 当您从`dosync`中"发送"代理时,它不会运行直到`dosync`结束.这意味着如果您的代理出现问题,则回滚STM事务为时已晚,如果您的代理正在访问数据库(数据库可能拒绝您的数据或服务器可能已关闭),则总是可能.我认为协调ref和数据库目前很难(或者不可能?)甚至使用代理. (4认同)
  • 对,打印到控制台和更新数据库表都有资格作为副作用.`dosync`块通常不应该包含副作用代码*,除了*调用事务感知的Ref修改函数(`alter` /`commute` /`ref-set`),重要的例外是任何动作发送给代理可能包含在事务完成后发生的副作用(如果事务提交,将执行所有此类操作,因此不存在导致相同副作用的风险一次). (2认同)