Clojure STM(dosync)x Java同步块

时间:2010-08-27 11:02:14

标签: 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))))

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

提前致谢! 丹塔斯

4 个答案:

答案 0 :(得分:19)

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代理(它只会执行如果事务成功提交,则为其任务。)

答案 1 :(得分:3)

除了Michał的优秀答案之外,对于STM交易,读取总是在交易开始时为您提供冻结价值,无需等待任何正在进行的交易完成。

答案 2 :(得分:3)

为了给那些寻求的人提供一个完整的图片,Clojure确实有一个synchronized模拟。当必须使用Java非线程安全类型进行互操作时,它非常有用。

(locking x & body)

答案 3 :(得分:0)

基本区别如下

Clojure STM支持乐观并发,而JAVA synchronized是悲观

在有多个线程之前,Clojure STM不会获取锁定。如果另一个线程更新了可变状态,则重复 dosync 中的操作。此外, dosync 对于可变状态是必需的。与JAVA不同,当丢失dosync时,Clojure会抛出illegalState异常。